Dear Youngtae Jo, thanks for your kindness on sharing your code. It pushed 
me to finally obtain some results.
However there are certain points that you need to take care on your code. I 
will try to list at least most of them here:

   1. you haven't set anything to the ADC_CLKDIV register. On my BBB, this 
   register is set to 7 by default, so the ADC Clock turns out to be 
   24MHz/(7+1) = 3 MHz, and the PRU's clock is not a multiple of it. So I 
   suggest to set the ADC_CLKDIV to something that divides the 24 MHz by 3 (2, 
   5, 11...). Check the SPRUH73L guide for more information on this register.
   2. your code will only work with the PRU0 because of the way things are 
   defined in the .hp file. I know you got it from the am335x github 
   
<https://github.com/beagleboard/am335x_pru_package/tree/master/pru_sw/example_apps/PRU_memAccess_DDR_PRUsharedRAM>,
 
   but I believe they didn't make a good job on that header file. You can 
   read more about this problem here 
   
<http://www.embedded-things.com/bbb/understanding-bbb-pru-shared-memory-access/>
   .
   3. that offset has no reason, I know it was also taken by the am335x 
   github file, but I believe they made that for pedagogical reasons only, as 
   it is an example so they are showing possibilities. I would set the C28 
   register to 0x100 so that it will point to the first shared memory address 
   (0x10000). Once that's done you can take rid of the offsets in the C code.
   4. your calculation on the number of loops is wrong. If you know the 
   sampling frequency, then you need the time step between two samples, then 
   you know how many 5 ns instructions fit on it. Finally divide it by 2, as 
   you did, as every loop takes 2 instructions.
   5. I believe that anyone coding an ADC capture in assembly is really 
   looking for some time precision, so you'd need to count every single 
   instruction you make outside of the delay loop and compensate that many 
   instructions in the loop. That's a tedious job as you need to make the 
   number of instructions even, and make that number be the same no matter 
   where the code jumps to.
   6. you have used bone_capemgr.8 but that could vary, and it does, as on 
   my BBB that number is 9.
   7. according to the SPRUH73L guide, the Enabled bit from the CTRL 
   register must be set only after all the steps configs are set.
   8. the first "sample" on the Results.txt file is actually the buffer 
   flag, I suggest to remove the first line to avoid misreadings.
   9. you have some divisions in your numerical defines, I don't recommend 
   that because one may have a numerator which is not a multiple of the 
   denominator and then he'll lose precision.
   10. I suggest a complete restructure of the communication between the C 
   code and the P code, so that you don't have to manually edit each parameter 
   twice. Sampling frequency, buffer size, you know...
   11. less important, but it would be great if you defined a register to 
   contain the ADC_TSC base register, and then define the offsets of the 
   others. It would have made your code more readable and flexible.
   12. you don't need to define PRUSS0_SHARED_DATARAM because it already 
   exists with that name in the pruss headers.
   13. you don't need the ProcessingADC1 function. According to the 
   SPRUH73L guide, the channel number will be printed together only if bit 1 
   is set, which is not the case.
   14. you can tune your code to use 16 bits for each sample, but as you 
   are using two buffers it doesn't seem to matter here.

Well those are some of the points that I dedicated for my final work and I 
decided to share with you as your code reeeally helped to go ahead.
Thank you *very* much!

Em terça-feira, 8 de abril de 2014 07:15:31 UTC-3, Youngtae Jo escreveu:
>
> I've tried to find some example of ADC reading by PRU for my project, but 
> I couldn't find it.
> And I made that of source code and attach here for some people who have 
> the same problem with me.
> I hope it will be helpful.
>
> [ AM335x ARM-CORE PRU ADC Example ]
>  - Sequence of example
>  1. Install compiling environment of PRU
>  2. Enable PRU 
>  3. Enable ADC 
>  4. Example source
>     - This example source collects ADC data from AIN0 pin with 16khz 
> sampling rate.
> - The collected data are saved into "Results.txt" file.
> - The example source are "Makefile", "ADCCollector.c", "ADCCollector.p", 
> "ADCCollector.hp"
>
> [ Install compile environment ]
>  1. Get a copy of the am335x_pru_package -> 
> https://github.com/beagleboard/am335x_pru_package
>     You also can download the am335x_pru_package here -> 
> https://github.com/beagleboard/am335x_pru_package/archive/master.zip
>  2. If you downloaded the archive, unpack it somewhere under your home 
> directory.
>  3. Make a new directory /usr/include/pruss/ and copy the files prussdrv.h 
>  
>     and pruss_intc_mapping.h into it (from 
> am335x_pru_package-master/pru_sw/app_loader/include). 
> Check the permissions; if you used the .zip file, these headers will 
> likely have the execute bits on. 
> It doesn't really hurt anything, but is certainly not what you want.
>  4. Change directory to 
> am335x_pru_package-master/pru_sw/app_loader/interface 
>     then run: CROSS_COMPILE= make (note the space between the = and the 
> command).
>  5. The previous step should have created four files in 
> am335x_pru_package-master/pru_sw/app_loader/lib: libprussdrv.a, 
> libprussdrvd.a, libprussdrvd.so and libprussdrv.so. 
>     Copy these all to /usr/lib then run ldconfig.
>  6. Change directory to am335x_pru_package-master/pru_sw/utils/pasm_source 
>     then run source linuxbuild to create a pasm executable one directory 
> level up. 
>  - If linuxbuild doesn't have permission to execution, give the permission 
> by run this
>    : chmod +x linuxbuild
> Copy it to /usr/bin and make sure you can run it. 
> If you invoke it with no arguments, you should get a usage statement.
>  
> [ Enable PRU ]
>  Before using PRU, we need to enable the PRU core, you can do it as shown 
> below
>  # echo BB-BONE-PRU-01 > /sys/devices/bone_capemgr.8/slots
>
> [ Enable ADC ]
>  Before using ADC, we also need to enable ADC, you can do it as shown below
>  # echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
>  
> [ ADC Example - Makefile]
> CFLAGS+=-Wall -Werror
> LDLIBS+= -lpthread -lprussdrv
>
> all: ADCCollector.bin ADCCollector
>
> clean:
> rm -f ADCCollector *.o *.bin
>
> ADCCollector.bin: ADCCollector.p
> pasm -b $^
>
> ADCCollector: ADCCollector.o
>
> [ ADC Example - ADCCollector.p]
> // Developed by Youngtae Jo in Kangwon National University (April-2014)
>
> // This program collects ADC from AIN0 with certain sampling rate.
> // The collected data are stored into PRU shared memory(buffer) first.
> // The host program(ADCCollector.c) will read the stored ADC data
> // This program uses double buffering technique. 
> // The host program can recognize the buffer status by buffer status 
> variable
> // 0 means empty, 1 means first buffer is ready, 2 means second buffer is 
> ready.
> // When each buffer is ready, host program read ADC data from the buffer.
>
>
> .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
> #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
>         ADD r5, r5, 4
>         //Write ADC to PRU Shared RAM
>         SBCO r3, CONST_PRUSHAREDRAM, r5, 4 
>
>         DELAY
>         
>         SUB r6, r6, 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
>
>     //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
>     MOV r2, 0x44E0D054
>     MOV r3, 0x00000002
>     SBBO r3, r2, 0, 4
>
>     //Init ADC STEPCONFIG 1
>     MOV r2, 0x44E0D064
>     MOV r3, 0x00000001 //continuous mode
>     SBBO r3, r2, 0, 4
>
>     //Read ADC and FIFOCOUNT
>     READADC
>
>
>
>
> [ ADC Example - ADCCollector.c]
>
>
> /******************************************************************************
> * Include Files                                                           
>     *
>
> ******************************************************************************/
> // Standard header files
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/mman.h>
> #include <fcntl.h>
> #include <errno.h>
> #include <unistd.h>
> #include <string.h>
> #include <time.h>
>
> // Driver header file
> #include <pruss/prussdrv.h>
> #include <pruss/pruss_intc_mapping.h>
>
>
> /******************************************************************************
> * Local Macro Declarations                                                 
>    * 
>
> ******************************************************************************/
> #define PRU_NUM  0
> #define OFFSET_SHAREDRAM 2048 //equivalent with 0x00002000
>
> #define PRUSS0_SHARED_DATARAM    4
> #define SAMPLING_RATE 16000 //16khz
> #define BUFF_LENGTH SAMPLING_RATE
> #define PRU_SHARED_BUFF_SIZE 500
> #define CNT_ONE_SEC SAMPLING_RATE / PRU_SHARED_BUFF_SIZE
>
>
> /******************************************************************************
> * Functions declarations                                                   
>    * 
>
> ******************************************************************************/
> static void Enable_ADC();
> static void Enable_PRU();
> static unsigned int ProcessingADC1(unsigned int value);
>
>
> /******************************************************************************
> * Global variable Declarations                                             
>    * 
>
> ******************************************************************************/
> static void *sharedMem;
> static unsigned int *sharedMem_int;
>
>
> /******************************************************************************
> * Main                                                                     
>    * 
>
> ******************************************************************************/
> int main (int argc, char* argv[])
> {
> FILE *fp_out;
>     unsigned int ret;
>     tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
> int i = 0, cnt = 0, total_cnt = 0;
> int target_buff = 1;
> int sampling_period = 0;
>
> if(argc != 2){
> printf("\tERROR: Sampling period is required by second\n");
> printf("\t       %s [sampling period]\n", argv[0]);
> return 0;
> }
> sampling_period = atoi(argv[1]);
>
> /* Enable PRU */
> Enable_PRU();
> /* Enable ADC */
> Enable_ADC();
> /* Initializing PRU */
>     prussdrv_init();
>     ret = prussdrv_open(PRU_EVTOUT_0);
>     if (ret){
>         printf("\tERROR: prussdrv_open open failed\n");
>         return (ret);
>     }
>     prussdrv_pruintc_init(&pruss_intc_initdata);
>     printf("\tINFO: Initializing.\r\n");
>     prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, &sharedMem);
>     sharedMem_int = (unsigned int*) sharedMem;
>  /* Open save file */
> fp_out = fopen("Results.txt", "w");
> if(fp_out == NULL){
> printf("\tERROR: file open failed\n");
> return 0;
> }
>
> /* Executing PRU. */
> printf("\tINFO: Sampling is started for %d seconds\n", sampling_period);
>     printf("\tINFO: Collecting");
>     prussdrv_exec_program (PRU_NUM, "./ADCCollector.bin");
> /* Read ADC */
> while(1){
> while(1){
> if(sharedMem_int[OFFSET_SHAREDRAM] == 1 && target_buff == 1){ // First 
> buffer is ready
> for(i=0; i<PRU_SHARED_BUFF_SIZE; i++){
> fprintf(fp_out, "%d\n", ProcessingADC1(sharedMem_int[OFFSET_SHAREDRAM + 1 
> + i]));
> }
> target_buff = 2;
> break;
> }else if(sharedMem_int[OFFSET_SHAREDRAM] == 2 && target_buff == 2){ // 
> Second buffer is ready
> for(i=0; i<PRU_SHARED_BUFF_SIZE; i++){
> fprintf(fp_out, "%d\n", ProcessingADC1(sharedMem_int[OFFSET_SHAREDRAM + 
> PRU_SHARED_BUFF_SIZE + 1 + i]));
> }
> target_buff = 1;
> break;
> }
> }
>
> if(++cnt == CNT_ONE_SEC){
> printf(".");
> total_cnt += cnt;
> cnt = 0;
> }
>
> if(total_cnt == CNT_ONE_SEC * sampling_period){
> printf("\n\tINFO: Sampling completed ...\n");
> break;
> }
> }
>
> fclose(fp_out);
>     printf("\tINFO: PRU completed transfer.\r\n");
>     prussdrv_pru_clear_event (PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
>
>     /* Disable PRU*/
>     prussdrv_pru_disable(PRU_NUM);
>     prussdrv_exit();
>
>     return(0);
> }
>
>
> /*****************************************************************************
> * Local Function Definitions                                               
>   *
>
> *****************************************************************************/
> /* Enable ADC */
> static int Enable_ADC()
> {
> FILE *ain;
>
> ain = fopen("/sys/devices/bone_capemgr.8/slots", "w");
> if(!ain){
> printf("\tERROR: /sys/devices/bone_capemgr.8/slots open failed\n");
> return -1;
> }
> fseek(ain, 0, SEEK_SET);
> fprintf(ain, "cape-bone-iio");
> fflush(ain);
> return 0;
> }
>
> /* Enable PRU */
> static int Enable_PRU()
> {
> FILE *ain;
>
> ain = fopen("/sys/devices/bone_capemgr.8/slots", "w");
> if(!ain){
> printf("\tERROR: /sys/devices/bone_capemgr.8/slots open failed\n");
> return -1;
> }
> fseek(ain, 0, SEEK_SET);
> fprintf(ain, "BB-BONE-PRU-01");
> fflush(ain);
> return 0;
> }
>
> /* 
>  * FIFO0DATA register includes both ADC and channelID
>  * so we need to remove the channelID
>  */
> static unsigned int ProcessingADC1(unsigned int value)
> {
> unsigned int result = 0;
>
> result = value << 20;
> result = result >> 20;
>
> return result;
> }
>
>
>
> [ ADC Example - ADCCollector.hp]
> // 
> *****************************************************************************/
> // file:   PRU_memAccess_DDR_PRUsharedRAM.hp
> //
> // brief:  PRU_memAccess_DDR_PRUsharedRAM assembly constants.
> //
> //
> //  (C) Copyright 2012, Texas Instruments, Inc
> //
> //  author     M. Watkins
> // 
> *****************************************************************************/
>
>
> #ifndef _PRU_memAccess_DDR_PRUsharedRAM_HP_
> #define _PRU_memAccess_DDR_PRUsharedRAM_HP_
>
>
> // ***************************************
> // *      Global Macro definitions       *
> // ***************************************
>
> // Refer to this mapping in the file - 
> \prussdrv\include\pruss_intc_mapping.h
> #define PRU0_PRU1_INTERRUPT     17
> #define PRU1_PRU0_INTERRUPT     18
> #define PRU0_ARM_INTERRUPT      19
> #define PRU1_ARM_INTERRUPT      20
> #define ARM_PRU0_INTERRUPT      21
> #define ARM_PRU1_INTERRUPT      22
>
> #define CONST_PRUCFG     C4
> #define CONST_PRUDRAM        C24
> #define CONST_PRUSHAREDRAM   C28
> #define CONST_DDR            C31
>
> // Address for the Constant table Block Index Register (CTBIR)
> #define CTBIR          0x22020
>
> // Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
> #define CTPPR_0         0x22028
>
> // Address for the Constant table Programmable Pointer Register 1(CTPPR_1)
> #define CTPPR_1         0x2202C
>
>
> .macro  LD32
> .mparam dst,src
>     LBBO    dst,src,#0x00,4
> .endm
>
> .macro  LD16
> .mparam dst,src
>     LBBO    dst,src,#0x00,2
> .endm
>
> .macro  LD8
> .mparam dst,src
>     LBBO    dst,src,#0x00,1
> .endm
>
> .macro ST32
> .mparam src,dst
>     SBBO    src,dst,#0x00,4
> .endm
>
> .macro ST16
> .mparam src,dst
>     SBBO    src,dst,#0x00,2
> .endm
>
> .macro ST8
> .mparam src,dst
>     SBBO    src,dst,#0x00,1
> .endm
>
>
> // ***************************************
> // *    Global Structure Definitions     *
> // ***************************************
>
> .struct Global
>     .u32 regPointer
>     .u32 regVal
> .ends
>
>
> // ***************************************
> // *     Global Register Assignments     *
> // ***************************************
>
> .assign Global, r2, *, global
>
> #endif //_PRU_memAccess_DDR_PRUsharedRAM_
>
>

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to