PaddleStroke 2 Posted August 27, 2020 Share Posted August 27, 2020 Hey guys, I'm trying to find a way to read the values of the LRADC0 and LRADC1 of the A20. Those ADC are usually used for android-style buttons (labeled "VOL+", "VOL-", "MENU", "SEARCH", "HOME", "ESC" and "ENTER") which are connected to a low-resolution ADC via a resistor network. But I want to use the ADC for another purpose and I just need to read values between 0 and 63. Now it seems there is already a driver which let you setup the android-style buttons in the DTS (as can be seen in this patch) But I can't find the code of this driver, which I could use as a template. Any idea how to find the driver ? Or on how to read the LRADC values from a python script directly? Thanks! Related, for reference : https://www.olimex.com/forum/index.php?topic=4281.0 https://www.olimex.com/forum/index.php?topic=2425.0 Edit: I think I found the driver : https://github.com/torvalds/linux/blob/master/drivers/input/keyboard/sun4i-lradc-keys.c To be continued. 0 Quote Link to post Share on other sites
martinayotte 674 Posted August 27, 2020 Share Posted August 27, 2020 31 minutes ago, PaddleStroke said: Or on how to read the LRADC values from a python script directly? Using /dev/mem, you can poke control register at 0x01C22800 to be in continuous mode, and then peek data register to read ADC values at 0x01C2280C or 0x01C2280D, depending if LRADC0 or LRADC1. 1 Quote Link to post Share on other sites
PaddleStroke 2 Posted September 22, 2020 Author Share Posted September 22, 2020 On 8/27/2020 at 4:11 PM, martinayotte said: Using /dev/mem, you can poke control register at 0x01C22800 to be in continuous mode, and then peek data register to read ADC values at 0x01C2280C or 0x01C2280D, depending if LRADC0 or LRADC1. Hi! Thanks for your reply ! I had to put that on hold for some time, but I'm back on it. After checking the A20 user manual I find that the offset for LRADC1 is 0x10 and not 0x0D. So I guess you meant 0x01C22810 for LRADC1? So I should be doing something like : fd = open("/dev/mem", "r+") mem = mmap.mmap(fd.fileno(), 16, 0x01C22800 ) close(fd) while(we need to get the values): mem.seek(0x0C) LRADC0_byte = mem.read(1) mem.seek(0x10) LRADC1_byte = mem.read(1) //further process the values mem.close() Does that sounds correct to you? 0 Quote Link to post Share on other sites
martinayotte 674 Posted September 22, 2020 Share Posted September 22, 2020 13 minutes ago, PaddleStroke said: So I should be doing something like : Right, but don't forget to initialize Control Register first by setting Continuous Rate and Continuous Mode... 1 Quote Link to post Share on other sites
PaddleStroke 2 Posted September 22, 2020 Author Share Posted September 22, 2020 1 hour ago, martinayotte said: Right, but don't forget to initialize Control Register first by setting Continuous Rate and Continuous Mode... Could you please tell me how to do this? I don't know what is the control register nor how to initialize it. 0 Quote Link to post Share on other sites
martinayotte 674 Posted September 22, 2020 Share Posted September 22, 2020 48 minutes ago, PaddleStroke said: Could you please tell me how to do this? I don't know what is the control register nor how to initialize it. Download this UserGuide : http://dl.linux-sunxi.org/A20/A20 User Manual 2013-03-22.pdf Read the LRADC chapter starting at page 192. You will see the description of the ControlRegister at page 193-194. You need your /dev/mem to be "O_RDWR", not "R+" to allow writing into ControlRegister. 1 Quote Link to post Share on other sites
PaddleStroke 2 Posted October 20, 2020 Author Share Posted October 20, 2020 Quote You need your /dev/mem to be "O_RDWR", not "R+" to allow writing into ControlRegister. Thanks! I can now read the values of the LRADC. Now I have only one issue left is that my python script does not have permission to read /dev/mem when it's started automatically at launch. I had the same permission issue when trying to read AXP209 ADC, which we solved by using a .rule file in etc/udev/rules. I tried to add one line for /dev/mem but I think I'm missing something here. ACTION=="add", SUBSYSTEM=="iio", RUN+="/bin/chmod g+w /sys/bus/iio/devices/iio:device0/in_voltage3_scale" ACTION=="add", SUBSYSTEM=="iio", RUN+="/bin/chmod g+w /sys/bus/iio/devices/iio:device0/in_voltage4_scale" ACTION=="add", SUBSYSTEM=="iio", RUN+="/bin/chmod g+w /sys/bus/iio/devices/iio:device0/in_voltage3_raw" ACTION=="add", SUBSYSTEM=="iio", RUN+="/bin/chmod g+w /sys/bus/iio/devices/iio:device0/in_voltage4_raw" ACTION=="add", RUN+="/bin/chmod g+w /dev/mem" I also tried : sudo chmod 777 /dev/men and sudo usermod -g kmem pi Then I have a different error "[Errno1] Operation not permitted: '/dev/mem' The working python script for reference : #!/usr/bin/env python from time import sleep import os, sys, mmap DZONE2 = 6 # dead zone applied to joystick (mV) VREF2 = 40 # max value read when moving joystick to max. JOYOFFVAL2 = 60 # Value reads 63 when not working #LRADC base register address = 0x01C22800 (cf A20 manual page 193) MAP_MASK = mmap.PAGESIZE -1 addr = 0x01C22800 fd = os.open("/dev/mem", os.O_RDWR | os.O_SYNC) mem = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, offset= addr & ~MAP_MASK) os.close(fd) #using mem.write_byte to write the 4 bytes of the control register one by one does not work. read_byte one by one also do not work. You need to read the 4 at once. So the following does not work : #mem.seek(addr & MAP_MASK) #mem.write_byte(chr(int('01111001', 2))) #mem.write_byte(chr(int('00100000', 2))) #mem.write_byte(chr(int('11000000', 2))) #mem.write_byte(chr(int('00000001', 2))) #The correct way to do it is to add the 4 bytes together as follow : mem.seek(addr & MAP_MASK) byte_data = [121, 32, 192, 1] mem.write("".join(map(chr, byte_data))) #121 = 0111 1001 is for bit 7 to 0 of the first byte (0x01C22800). Bit 6 and 5 '11' are for reference voltage to use, here 11 = 1.6V. Bit 0 is to activate the LRADC. #32 = 0010 0000 is for bit 7 to 0 of the 2nd byte (0x01C22801). Bit 13 and 12 '10' are for continuous mode. #192 = 1100 0000 is for bit 7 to 0 of the 3rd byte (0x01C22802). Bit 23 and 22 '11' are to enable both LRADC0 and LRADC1. #1 = 0000 0001 is default value. mem.seek(addr & MAP_MASK) print("bytes") ciuy = mem.read(4) print(' '.join(format(ord(x), 'b') for x in ciuy)) while True: mem.seek((0x01C2280C)& MAP_MASK) # register offset for LRADC0 = 0x0C joystick2_UD = ord(mem.read_byte()) #should be between 0 and 63 (6 bits) mem.seek((0x01C22810)& MAP_MASK) # register offset for LRADC1 = 0x10 joystick2_LR = ord(mem.read_byte()) #should be between 0 and 63 (6 bits) if (joystick2_LR > (VREF2/2 + DZONE2)) or (joystick2_LR < (VREF2/2 - DZONE2)): #print(' '.join(format(ord(x), 'b') for x in joystick2_LR)) print("Right Joystick LR : ", joystick2_LR) if (joystick2_UD > (VREF2/2 + DZONE2)) or (joystick2_UD < (VREF2/2 - DZONE2)): #print(' '.join(format(ord(x), 'b') for x in joystick2_UD)) print("Right Joystick UD : ", joystick2_UD) sleep(.2) mem.close() 0 Quote Link to post Share on other sites
martinayotte 674 Posted October 20, 2020 Share Posted October 20, 2020 1 hour ago, PaddleStroke said: my python script does not have permission to read /dev/mem You can try a workaround by doing "cp /usr/bin/python /usr/bin/python-sudo ; chmod a+s /usr/bin/python-sudo" so that execution will be done as root. 1 Quote Link to post Share on other sites
PaddleStroke 2 Posted October 21, 2020 Author Share Posted October 21, 2020 Thanks! I went with chmod a+s /usr/bin/python And it's working now! Thanks again for your support. I think I should make a proper gamepad kernel module rather than this python script. For reference, the python script is launched as a service in systemd. By the way I made a video on the hardware part of prototyping, maybe it will interest some people 0 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.