This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADC SOC EOC bits with AM335x

Hello everyone,

I am trying to read the analog inputs (AIN0 and AIN1) from the ADC using an AM335x processor. The problem that I have is related to enable these two channels and to synchronize the reading from each channel. I have been looking in the reference manual how to use the SOC and EOC bits in order to know when the start and the end of conversion happen for every input, but I didn’t find any information so far about this. I am using the PRU to read from the ADC and this is my code until today:

 

.origin 0 // offset of the start of the code in PRU memory

.entrypoint START // program entry point, used by debugger only

 

#include "ADCCollector.hp"

 

#define BUFF_SIZE 0x00000FA0 //Total buff size: 4kbyte(Each buffer has 2kbyte: 500 piece of data)

#define HALF_SIZE BUFF_SIZE / 2

 

#define SAMPLING_RATE 16000 //Sampling rate(16khz)

#define DELAY_MICRO_SECONDS (1000000 / SAMPLING_RATE) //Delay by sampling rate (62us for ADC reading)

#define CLOCK 200000000 // PRU is always clocked at 200MHz

#define CLOCKS_PER_LOOP 2 // loop contains two instructions, one clock each

#define DELAYCOUNT DELAY_MICRO_SECONDS * CLOCK / CLOCKS_PER_LOOP / 1000 / 1000 * 3

 

.macro DELAY

    MOV r10, DELAYCOUNT

    DELAY:

        SUB r10, r10, 1

        QBNE DELAY, r10, 0

.endm

 

.macro READADC

    //Initialize buffer status (0: empty, 1: first buffer is ready, 2: second buffer is ready)

    MOV r2, 0

    SBCO r2, CONST_PRUSHAREDRAM, 0, 4

 

    INITV:

        MOV r5, 0 //Shared RAM address of ADC Saving position

        MOV r6, BUFF_SIZE  //Counting variable

 

    READ:

        //Read ADC from FIFO0DATA

        MOV r2, 0x44E0D100

        LBBO r3, r2, 0, 4

        //Add address counting (Shared RAM)

        ADD r5, r5, 4

        //Write ADC to PRU Shared RAM

        SBCO r3, CONST_PRUSHAREDRAM, r5, 4

 

        DELAY

 

        SUB r6, r6, 4   // Reduce the BUFF_SIZE counter

        MOV r2, HALF_SIZE

        // Quick Branch if Equal

        QBEQ CHBUFFSTATUS1, r6, r2 //If first buffer is ready

        QBEQ CHBUFFSTATUS2, r6, 0 //If second buffer is ready

        // Quick Branch Always

        QBA READ

 

    //Change buffer status to 1 (first buffer is full)

    CHBUFFSTATUS1:

        MOV r2, 1

        SBCO r2, CONST_PRUSHAREDRAM, 0, 4

        QBA READ

 

    //Change buffer status to 2 (second buffer is full)

    CHBUFFSTATUS2:

        MOV r2, 2

        SBCO r2, CONST_PRUSHAREDRAM, 0, 4

        QBA INITV

 

    //Send event to host program

    MOV r31.b0, PRU0_ARM_INTERRUPT+16

    HALT

.endm

 

// Starting point

START:

    // Enable OCP master port

    LBCO r0, CONST_PRUCFG, 4, 4

    CLR r0, r0, 4

    SBCO r0, CONST_PRUCFG, 4, 4

 

    //C28 will point to 0x00012000 (PRU shared RAM)

    MOV r0, 0x00000120

    MOV r1, CTPPR_0

    ST32 r0, r1

 

    //Init ADC CTRL register

    MOV r2, 0x44E0D040

    MOV r3, 0x00000005

    SBBO r3, r2, 0, 4

 

    //Enable ADC STEPCONFIG 1 and 2 (STEPENABLE msg)

    MOV r2, 0x44E0D054

    MOV r3, 0x00000006

    SBBO r3, r2, 0, 4

 

    //Init ADC STEPCONFIG 1

    MOV r2, 0x44E0D064

    MOV r3, 0x00000001 //continuous mode

    SBBO r3, r2, 0, 4

 

    //Init ADC STEPCONFIG 2

    MOV r2, 0x44E0D06C

    MOV r3, 0x00000001 //continuous mode

    SBBO r3, r2, 0, 4

 

    //Read ADC and FIFOCOUNT

    READADC

 

Could you please help me to find which register I have to use to check these two bits? 

  • Hi Antonio,

    welcome to our forum.

    I don't know if I missed the information in your post, but which ADC exactly are you trying to interface with?

    Regards,

  • Hi Joachim,

    Thank you for your reply. I am trying to interface AN0 and AN1. This is the part of the code that I have used to enable these two analog inputs:

    //Enable ADC STEPCONFIG 1 and 2 (STEPENABLE msg)

        MOV r2, 0x44E0D054

        MOV r3, 0x00000006

        SBBO r3, r2, 0, 4

     

        //Init ADC STEPCONFIG 1

        MOV r2, 0x44E0D064

        MOV r3, 0x00000001 //continuous mode

        SBBO r3, r2, 0, 4

     

        //Init ADC STEPCONFIG 2

        MOV r2, 0x44E0D06C

        MOV r3, 0x00080001 //continuous mode

        SBBO r3, r2, 0, 4

    Unfortunately I can only get the input from AN0. Can you tell me what I am doing wrong? or maybe you can show me some alternative solution.

    Thank you for your help

  • Hello sir. I was wondering if you managed to read from both AIN0 and AIN1 at the same time. I f you did and you don't mind sharing the solution with me I will appreciate it. One more question please, in my project I have to read from all 7 inputs, what do I have to change? ANd if I want to increase the sampling rate, what is the maximum value I can reach? And how to do so?

  • Antonio,

    I've moved this post into the Sitara Processors forum. I think the problem was that your original post went into the Precision Data Converter forum, where we handle standalone data converters from 12 to 24 to higher bit counts.

    Now, that this is in the proper forum, it should get an answer. Sorry about the late response.

    Joseph Wu

  • AM335x has one ADC that is connected to the output of a analog multiplexer which has 8 inputs connected to AIN[7:0]. Since there is only one ADC is is not possible to sample multiple analog inputs at the same time. The ADC can be configured to sample a single analog input or time division multiplex (TDM) multiple analog inputs. The sample rate of the ADC is shared by all of the analog inputs when using TDM, so the sample rate of the analog inputs will be the ADC sample rate divided by the number of analog inputs being sampled. The maximum sample rate of the ADC is 200 ksps.

    Regards,
    Paul

  • Hello sir,

    I would like to read all 7 inputs in a loop form:

    while( n*7 < sampling_rate){ //initial value for n = 0

    read(AIN0); //and store it in shared memory(7*n + 0)

    read(AIN1); //and store it in shared memory(7*n + 1)

    read(AIN2); //and store it in shared memory(7*n + 2)

    read(AIN3); //and store it in shared memory(7*n + 3)

    read(AIN4); //and store it in shared memory(7*n + 4)

    read(AIN5); //and store it in shared memory(7*n + 5)

    read(AIN6); //and store it in shared memory(7*n + 6)

    n++;

    }

    so that I can read them from a host program running on the main processor. Any idea how to do so? 

    Another question is: if I simply changed the #define Samplig_rate from 16000 to any other number below 200000, I will get that sampling rate? or should I change other things?

    Thanks in advance. 

  • Please do not duplicate your posts....there is another one here:

    http://e2e.ti.com/support/arm/sitara_arm/f/791/t/371252.aspx

  • Ok sir, but I actually posted that question after I commented on this post because I thought it would be better to have it in a separate post. Sorry about that.

  • I cannot help you with software related questions.  For example, I do not know anything about the read commands you are using.  However, I can describe how the Touch screen controller must be configured for your application.

    Please read the Touch Screen Controller chapter of the AM335x TRM to better understand how the ADC works.

    The touchscreen controller would need to be configured to operate in software enabled, continuous mode with 8 steps enabled and each step configured to sample one of the 8 inputs. The ADC clock should be configured to operate at 3MHz to get the maximum sample rate of 200 ksps. Each step should be configured to store its sampled data into one of the 2 FIFOs and it may be helpful to enable STEP_ID_TAG so software knows which data value stored in the FIFO is associated with a specific step/input.

    Each FIFO can be serviced by the processor or DMA. The user can individually enable or disable each FIFO DMA request via the DMAENABLE_SET and DMAENABLE_CLR registers. A DMA request is generated when the value of  IFO0COUNT/FIFO1COUNT registers equals the word count threshold programmed in the respective DMA0REQ/DMA1REQ registers.

    With this configuration, the ADC would continuously sample each input at 25 ksps (200 ksps /8) and automatically store the values in a FIFO that triggers a DMA when it fills to a programmed threshold and the DMA would move the data into memory and notify the processor.

    Regards,
    Paul

  • Thank you sir for you help. I did what you said and it's somehow working but I have a small problem.

    I did the following configurations as you suggested 

    //Init ADC CTRL register
        MOV r2, 0x44E0D040
        MOV r3, 0x00000007 //5
        SBBO r3, r2, 0, 4
        
        //set clk div to 0
        mov r2,0x44e0d04c
        mov r3, 0x00000000
        SBBO r3, r2, 0, 4
    
        //Enable ADC STEPCONFIG 1-7
        MOV r2, 0x44E0D054
        MOV r3, 0x000000fe
        SBBO r3, r2, 0, 4
        
        
    
        //Init ADC STEPCONFIG 1
        MOV r2, 0x44E0D064
        MOV r3, 0x00000000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 2
        MOV r2, 0x44E0D06c
        MOV r3, 0x00080000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 3
        MOV r2, 0x44E0D074
        MOV r3, 0x00100000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 4
        MOV r2, 0x44E0D07c
        MOV r3, 0x00180000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 5
        MOV r2, 0x44E0D084
        MOV r3, 0x00200000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 6
        MOV r2, 0x44E0D08c
        MOV r3, 0x00280000 //one-shot mode
        SBBO r3, r2, 0, 4
        
        //Init ADC STEPCONFIG 7
        MOV r2, 0x44E0D094
        MOV r3, 0x00300000 //one-shot mode
        SBBO r3, r2, 0, 4

    If I'm not wrong, these configurations can be used to read from all 7 analog inputs using the following:

    .macro READADC
        //Initialize buffer status (0: empty, 1: first buffer is ready, 2: second buffer is ready)
        MOV r2, 0
        SBCO r2, CONST_PRUSHAREDRAM, 0, 4 
    
        INITV:
            MOV r5, 0 //Shared RAM address of ADC Saving position 
            MOV r6, BUFF_SIZE  //Counting variable 
    
        READ:
            //Read ADC from FIFO0DATA
            MOV r2, 0x44E0D100
            
            ////////////////////////////////////////////
            mov r1, 0x7
            mov r7, 0
            rree:LBBO r3, r2, r7, 4 
            //Add address counting
            ADD r5, r5, 4
            //Write ADC to PRU Shared RAM
            SBCO r3, CONST_PRUSHAREDRAM, r5, 4
            sub r1,r1,1
            add r7,r7,4
            qbne rree,r1,0
            ////////////////////////////////////////////
    
            
    
            DELAY
            
            SUB r6, r6, 0x1c //4
            MOV r2, HALF_SIZE
            QBEQ CHBUFFSTATUS1, r6, r2 //If first buffer is ready
            QBEQ CHBUFFSTATUS2, r6, 0 //If second buffer is ready
            QBA READ
    
        //Change buffer status to 1
        CHBUFFSTATUS1:
            MOV r2, 1 
            SBCO r2, CONST_PRUSHAREDRAM, 0, 4
            QBA READ
    
        //Change buffer status to 2
        CHBUFFSTATUS2:
            MOV r2, 2
            SBCO r2, CONST_PRUSHAREDRAM, 0, 4
            QBA INITV
    
    
     //Init ADC CTRL register
        MOV r2, 0x44E0D040
        MOV r3, 0x00000006
        SBBO r3, r2, 0, 4
        
        
     //Disable ADC STEPCONFIG 1-7
        //MOV r2, 0x44E0D054
        //MOV r3, 0x00000000
        //SBBO r3, r2, 0, 4
        
        
        
        //Send event to host program
        MOV r31.b0, PRU0_ARM_INTERRUPT+16 
        
        
       
        
        
        HALT
    .endm
    

    Now my problem is somehow silly but it will affect my results. When reading the values from the host code, I can use the line code:    (sharedMem_int[OFFSET_SHAREDRAM + 1 + i] & 0x000f0000) >> 16   to know from which analog pin the value came from (using the ID tag). The problem is that the pins are not fairly multiplexed (I mean that the TDM is not fair with all the pins). I might get values from pin0, pin1, pin1, pin1, pin2, ... (Notice that there are some consecutive values that came from the same pin). How can I force the program to read the values in a fair way (0,1,2,3,4,5,6,0,1,...)? 

    Another question is how to force the program to start reading always from AIN0? and how to let the PRU release the devices or the resource after halting (or immediately before halting)? When I execute the code and then try running the following command in the terminal:     cat /sys/devices/ocp.3/helper.15/AIN0     I get an error :  Resource or Device busy   although I used the instructions:

     //Disable ADC STEPCONFIG 1-7
        MOV r2, 0x44E0D054
        MOV r3, 0x00000000
        SBBO r3, r2, 0, 4

    Thank you again for you help.