Jump to content

Vini

Members
  • Posts

    2
  • Joined

  • Last visited

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. I have now had a look at the other ADC. It is quite harder to configure since it has 3 functionalities (CPU temperature sensor, or resistive Touch Panel controller, or single-ended ADC), but I was able to figure it out enough to use it. If you use the ADC, you must interrupt the other functionalities or build a driver to cope with them (temperature sensor and Touch Panel/ADC). Note that I am using Python 3 (because I'm familiar with it) to configure the ADC and read the ADC's values, which is probably very slow. A C/C++ program would be way faster in that regard (e.g., the code used to acquire the CPU temperature: https://github.com/armbian/build/blob/e9fb9542c763a88c8e689c3a14fc135bccea55f1/packages/bsp/sunxi-temp/sunxi_tp_temp.c). Here is the code for those that it could interest. #!/usr/bin/env python3 """ To use this script you must remove kernel drivers related to the A20's adc. Note that this script has been developped on a pcDuino 3, running on Armbian (Linux pcduino3 5.15.13-sunxi #trunk.0004 SMP Wed Jan 5 17:53:11 UTC 2022 armv7l GNU/Linux) The values registers have been set using the A20 Allwinner User Manual and by reverse engineering the previous OS images released by the pcDuino 3 teams in order to find a correct configuration. (pcDuino3 OS iso used: pcduino3_dd_sdbootable_20141110) You can list them: $ sudo lsmod | grep adc axp20x_adc 16384 0 sun4i_gpadc_iio 16384 0 industrialio 57344 2 sun4i_gpadc_iio,axp20x_adc sun4i_gpadc 16384 0 And remove them temporaly from the kernel using: $ sudo rmmod sun4i_gpadc_iio $ sudo rmmod sun4i_gpadc Blacklisting the modules would remove the need of runing the rmmod. WARNING: Note that removing the access to this ADC is probably removing the access to the temperature sensor. """ from time import sleep import os import mmap # Activate or deactivate the debug print DEBUG = False # Check CPU a20 = "sun7i" in open("/proc/cpuinfo", "r").read() if not a20: exit("This program only works on Allwinner sun7i (A20) cpus.") # TP register base address = 0x01C25000 (cfr. A20 manual page 205) TP_BASE_ADDRESS = 0x01C25000 # TP Control Register0 TP_CTRL0 = TP_BASE_ADDRESS + 0x00 # TP Control Register1 TP_CTRL1 = TP_BASE_ADDRESS + 0x04 # TP Pressure Measurement and touch sensitive Control Register TP_CTRL2 = TP_BASE_ADDRESS + 0x08 # Median and averaging filter Controller Register TP_CTRL3 = TP_BASE_ADDRESS + 0x0c # TP Interrupt FIFO Control Reg TP_INT_FIFOC = TP_BASE_ADDRESS + 0x10 # TP Interrupt FIFO Status Register TP_INT_FIFOS = TP_BASE_ADDRESS + 0x14 # TP Temperature Period Register TP_TPR = TP_BASE_ADDRESS + 0x18 # TP Common Data TP_CDAT = TP_BASE_ADDRESS + 0x1c # Temperature Data Register TEMP_DATA = TP_BASE_ADDRESS + 0x20 # TP Data Register TP_DATA = TP_BASE_ADDRESS + 0x24 # TP IO Configuration TP_IO_CONFIG = TP_BASE_ADDRESS + 0x28 # TP IO Port Data TP_PORT_DATA = TP_BASE_ADDRESS + 0x2c MAP_MASK = mmap.PAGESIZE - 1 def write(file, address, content: bytearray): """Write the content at a specific address and check success. Return the success of the operation. """ file.seek(address) file.write(content) file.seek(address) return file.read(len(content)) == content def print_all(mem): """Print the binary value of all the registers related to the ADC.""" mem.seek(TP_CTRL0 & MAP_MASK) print("TP_CTRL0:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_CTRL1 & MAP_MASK) print("TP_CTRL1:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_CTRL2 & MAP_MASK) print("TP_CTRL2:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_CTRL3 & MAP_MASK) print("TP_CTRL3:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_INT_FIFOC & MAP_MASK) print("TP_INT_FIFOC", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_INT_FIFOS & MAP_MASK) print("TP_INT_FIFOS", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_TPR & MAP_MASK) print("TP_TPR :", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_CDAT & MAP_MASK) print("TP_CDAT:", [bin(d) for d in list(mem.read(4))]) mem.seek(TEMP_DATA & MAP_MASK) print("TEMP_DATA:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_DATA & MAP_MASK) print("TP_DATA:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_IO_CONFIG & MAP_MASK) print("TP_IO_CONFIG:", [bin(d) for d in list(mem.read(4))]) mem.seek(TP_PORT_DATA & MAP_MASK) print("TP_PORT_DATA:", [bin(d) for d in list(mem.read(4))]) try: mem = mmap.mmap(os.open("/dev/mem", os.O_RDWR | os.O_SYNC), mmap.PAGESIZE, mmap.MAP_SHARED, offset=TP_BASE_ADDRESS & ~MAP_MASK) if DEBUG: print("Register initial") print_all(mem) # The correct way to do it is to add the 4 bytes together as follow : REGISTERS_CONFIG0 = bytearray(( # Bit 15:0 TACQ. # Touch panel ADC acquire time CLK_IN/(16*(N+1)) 0b00111111, 0b00000000, # Bit 23 ADC_FIRST_DLY_MODE. # ADC First Convert Delay Mode Select: # 0: CLK_IN/16, and 1: CLK_IN/16*256 # Bit 22 ADC_CLK_SELECT. # ADC Clock Source Select: # 0: HOSC(24MHZ), and 1: Audio PLL # Bit 21:20 ADC_CLK_DIVIDER. # ADC Clock Divider(CLK_IN) # 00: CLK/2, 01: CLK/3, 10: CLK/6, and 11: CLK/1 # Bit 19:16 FS_DIV. # ADC Sample Frequency Divider # xxxx: CLK_IN/2^(20-xxxx) 0b00111111, # Bit 31:24 ADC_FIRST_DLY. # ADC First Convert Delay Time(T_FCDT)setting # Based on ADC First Convert Delay Mode select (Bit 23) # T_FCDT = ADC_FIRST_DLY * ADC_FIRST_DLY_MODE 0b0 ) ) write(mem, TP_CTRL0 & MAP_MASK, REGISTERS_CONFIG0) REGISTERS_CONFIG1 = bytearray(( # Bit 7 CHOP_TEMP_EN # Chop temperature calibration enable # 0: Disable, and 1: Enable # Bit 6 TOUCH_PAN_CALI_EN. # Touch Panel Calibration # 1: start Calibration, it is clear to 0 after calibration # Bit 5 TP_DUAL_EN. # Touch Panel Double Point Enable # 0: Disable, and 1: Enable # Bit 4 TP_MODE_EN. # Tp Mode Function Enable # 0: Disable, and 1: Enable # Bit 3 TP_ADC_SELECT. # Touch Panel and ADC Select: # 0: TP, and 1: ADC # Bit 2:0 ADC_CHAN_SELECT. # Analog input channel Select In Normal mode: # 000: X1 channel, 001: X2 Channel # 010: Y1 Channel, 011: Y2 Channel # 1xx : 4-channel robin-round # FIFO Access Mode, based on this setting # Selecting one channel, FIFO will access that channel data; # Selecting four channels FIFO will access each channel data # in successive turn, first is X1 data. 0b00011000, # Bit 19(15):12 STYLUS_UP_DEBOUNCE. # See under # Bit 11:10 # Bit 9 STYLUS_UP_DEBOUCE_EN. # Stylus Up De-bounce Function Select # 0: Disable, and 1: Enable # Bit 8 / 0b00000000, # Bit 23:20 / # Bit 19:(16)12 STYLUS_UP_DEBOUNCE. # Stylus Up De-bounce Time setting # 0x00: 0 # …. # 0xff: 2N*(CLK_IN/16*256) 0b00000000, # Bit 31:24 / 0b00000000 ) ) write(mem, TP_CTRL1 & MAP_MASK, REGISTERS_CONFIG1) REGISTERS_CONFIG2 = bytearray(( 0b00000000, 0b00000000, 0b00000000, 0b11110100 ) ) write(mem, TP_CTRL2 & MAP_MASK, REGISTERS_CONFIG2) REGISTERS_CONFIG3 = bytearray(( # Bit 31(7):3 / # Bit 2 FILTER_EN. # Filter Enable # 0: Disable, and 1: Enable # Bit 1:0 FILTER_TYPE. # Filter Type: # 00: 4/2, 01: 5/3, 10: 8/4, and 11: 16/8 0b00000101, # Bit 31:(8)3 / 0b00000000, 0b00000000, 0b00000000 ) ) write(mem, TP_CTRL3 & MAP_MASK, REGISTERS_CONFIG3) REGISTERS_CONFIGFIFOC = bytearray(( 0b00000000, 0b00000000, 0b00000001, 0b00000000 ) ) write(mem, TP_INT_FIFOC & MAP_MASK, REGISTERS_CONFIGFIFOC) REGISTERS_TPR = bytearray(( 0b00000000, 0b00000000, 0b00000000, 0b00000000 ) ) write(mem, TP_TPR & MAP_MASK, REGISTERS_TPR) REGISTERS_CONFIGIO = bytearray(( # Bit 7 / # Bit 6:4 TX_N_SELECT # TX_N Port Function Select: # 000:Input, 001:Output, and 010: TP_XN # Bit 3 / # Bit 2:0 TX_P_SELECT # TX_P Port Function Select: # 000:Input, 001:Output, and 010: TP_XP 0b00100010, # 0b00000000, # All inputs # 0b00010001, # All inputs # Bit 14:12 TY_N_SELECT # TY_N Port Function Select: # 000:Input, 001:Output, and 010: TP_YN # Bit 11 / # Bit 10:8 TY_P_SELECT # TY_P Port Function Select: # 000:Input, 001:Output, and 010: TP_YP 0b00100010, # 0b00000000, # All inputs # 0b00010001, # All inputs # Bit 31:15 / 0b00000000, 0b00000000 ) ) write(mem, TP_IO_CONFIG & MAP_MASK, REGISTERS_CONFIGIO) if DEBUG: print("Final config") print_all(mem) while True: for adc in (0, 1, 2, 3): if DEBUG: print(f"\nA{adc+2} {45 * '='}") print_all(mem) print() # Select the ADC write(mem, TP_CTRL1 & MAP_MASK, bytearray( (0b00011000 | adc, 0b00000000, 0b00000000, 0b00000000))) # LED some times to the ADC logic to set the value sleep(0.01) mem.seek(TP_DATA & MAP_MASK) LSB, MSB = mem.read(2) print(f"A{adc+2}: {(MSB << 8) + LSB}", sep=" ") print() finally: mem.close()
  2. Hello, Interesting topic. I played with a pcDuino3 and the pin LRADC0 and 1 are mapped to A0 and A1. There are other ADCs mapped to the A2 to A5 pins (XP_TP, XN_TP, YP_TP and YN_TP), but I did not play with them yet. I slightly changed your code to port it to Python 3: #!/usr/bin/env python3 from time import sleep import os import mmap # Check CPU a20 = "Allwinner sun7i (A20)" in open("/proc/cpuinfo", "r").read() if not a20: exit("This program only works on Allwinner sun7i (A20) cpus.") # LRADC register base address = 0x01C22800 (cfr. A20 manual page 193) LRADC_BASE_ADDRESS = 0x01C22800 """ # LRADC Control Register LRADC_CTRL = LRADC_BASE_ADDRESS + 0x00 # LRADC Interrupt Control Register LRADC_INTC = LRADC_BASE_ADDRESS + 0x04 # LRADC Interrupt Status Register LRADC_INTS = LRADC_BASE_ADDRESS + 0x08 """ # LRADC Data Register 0 LRADC_DATA0 = LRADC_BASE_ADDRESS + 0x0c # LRADC Data Register 1 LRADC_DATA1 = LRADC_BASE_ADDRESS + 0x10 MAP_MASK = mmap.PAGESIZE - 1 try: mem = mmap.mmap(os.open("/dev/mem", os.O_RDWR | os.O_SYNC), mmap.PAGESIZE, mmap.MAP_SHARED, offset=LRADC_BASE_ADDRESS & ~MAP_MASK) # The correct way to do it is to add the 4 bytes together as follow : mem.seek(LRADC_BASE_ADDRESS & MAP_MASK) REGISTERS_CONFIG = bytearray(( # 0111 1001 is for bit 7 to 0 of the first byte (0x01C22800). # Bit 7 / # Bit 6 is LRADC sample hold # Bit 5:4 '11' are for reference voltage to use, where: # 00 ≈ 1.9 V, 01 ≈ 1.8V, 10 ≈ 1.7V, and 11 ≈ 1.6V # Bit 3:2 is the sampling rate, where: # 00 = 250 Hz, 01 = 125 Hz, 10 = 62.5 Hz, and 11 = 32.25 Hz. # Bit 1 / # Bit 0 is to activate the LRADC. 0b01000001, # 0010 0000 is for bit 7 to 0 of the 2nd byte (0x01C22801). # Bit 13 and 12 '10' are for continuous mode. # 1100 0000 is for bit 7 to 0 of the 3rd byte (0x01C22802). 0b00100000, # Bit 23 and 22 '11' are to enable both LRADC0 and LRADC1. 0b11000000, # 1 = 0000 0001 is default value. 0b00000001 ) ) mem.write(REGISTERS_CONFIG) mem.seek(LRADC_BASE_ADDRESS & MAP_MASK) check_register_config = mem.read(4) == REGISTERS_CONFIG print(f"Check LRADC config: {'ok' if check_register_config else 'failed'}") while True: mem.seek(LRADC_DATA0 & MAP_MASK) # should be between 0 and 63 (6 bits) print(f"LRADC0 (A0): {mem.read_byte()}") mem.seek(LRADC_DATA1 & MAP_MASK) # should be between 0 and 63 (6 bits) print(f"LRADC1 (A1): {mem.read_byte()}") sleep(0.2) finally: mem.close()
×
×
  • Create New...

Important Information

Terms of Use - Privacy Policy - Guidelines