Lenny, I'm sorry for this very late answer, but I found this topic really 
useful and you guys have given me the right directions.
I got to check all the information you gave here in the SPRUH73 guide 
(technical ashsssfyiafgygrf) and definitely, if one uses the default 3MHz 
ADC clock or the CLK_M_OSC 24MHz clock, that wouldn't perfectly sync with 
the PRUs as 200MHz is not a multiple of these values.
However, if I understood correctly, the PRCM acts like a prescaler, so 
maybe if you set PRCM = multiple of 3, do the clocks sync then?
I know, maybe you REALLY need the whole 24MHz... But in case your 
application accepts 8MHz, there's a chance of syncing them.

What do you think?

Em segunda-feira, 22 de dezembro de 2014 22:59:10 UTC-2, Lenny escreveu:
>
> Hi TJF and luciano, 
>
> below you can find the assembler code which I used. The critical 
> configuration step is this one
>     //ADC_CLKDIV
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000   //the 24MHz-clock rate is divided by VALUE+1 to 
> yield ADC_CLOCK 
>     SBBO VALUE,ADDR,0x4C,4 //important to write all 4 bytes even though 
> only the first 2 count - if this is not done, the change doesnt take effect 
> for some reason  
>
> For some reason, I struggled for some time believing that the ADC_CLKDIV 
> register was set to zero. Finally, all read and write operations went wrong 
> if I only did a 1 or 2 Byte read/write operation to the register. It only 
> worked properly when I read/wrote a full 4 Bytes to the register. 
>
> The main loop of my program arms a single ADC acquisition per cycle, waits 
> for some time, and then retrieves a single value from the FIFO. There are 
> two sources of timing jitter: 
> 1) The read operation from the FIFO takes on my BBB something between 42 
> and 44 PRU clock cycles. This is as far as I observed not fully 
> deterministic (some memory bus synchronization issue i guess). The solution 
> for this which I used is to have PRU0 running just as a timer (and 
> performing some well-timed calculations in the meantime), and let the PRU1, 
> after it has retrieved a new ADC value, stall until PRU0 has finished its 
> well-defined number of clock cycles and launch a new acquisition only after 
> the PRU0-PRU1 synchronisation has taken place. If one is careful about the 
> number of clock cycles per loop and the moments when one arms and reads out 
> the ADC, then this method only costs a few (<10) clock cycles but improves 
> control over the sampling time a lot.
>
> 2) As far as I observed, the ADC clock is not synchronized with the PRU 
> clock. So if the loop frequency is not a fraction of 24 MHz, there is a 
> "beating" between the two processes. If the loop frequency is a fraction of 
> 24 MHz, then there is from time to time a "glitch" between the two clocks. 
> I used the code below for a PID controller. When I set it to pure 
> proportional response, I observe random jumps in the group delay by 
> 1/24MHz. For my application this is not a problem. However, after knowing 
> this, if I would do this again, I would use an external ADC triggered by 
> the PRU for exactly this reason. If you should happen to find a way to 
> internally synchronize the ADC and PRU clocks, I would be really grateful 
> for a comment. 
>
> With all this working, I can read data from a single ADC channel and 
> output this on the r30 register pins (hooked to a parallel DAC) at 1.4 MHz 
> rate (im not using the full 1.6 MHz because of the random glitches in point 
> 2) with only a few degrees phase jitter, again due to point 2). If the 
> synchronization with two PRUs interests you, you can also check out the 
> full code for both PRU's in the attached zip file. 
>
> //prucode.hp
> #define ADC_TSC    0x44E0D000
> #define FIFO0COUNT 0x44E0D0E4
> #define FIFO0DATA  0x44E0D100
>
> //Register usage for PRU1
>
> #define CALLREG r0.w2
> #define ENABLESTEPBUFFER r0.b0
> #define DIVISORSHIFT r0.b1
>
> //Registers holding constants
> #define ADC_ADDR r1
> #define OUTMASK r2
>
> //Temporary values - used only for setup routines
> #define ADDR r3
> #define VALUE r4
>
> #define X0 r4
>
> .macro PAUSE
>     QBNE ENDPROGRAM,r0,r0
> .endm
>
> .macro PAUSE10
>     PAUSE
>     PAUSE
>     PAUSE
>     PAUSE
>     PAUSE
>     
>     PAUSE
>     PAUSE
>     PAUSE
>     PAUSE
>     PAUSE
> .endm
>
> .macro PAUSE100
>     PAUSE10
>     PAUSE10
>     PAUSE10
>     PAUSE10
>     PAUSE10
>     
>     PAUSE10
>     PAUSE10
>     PAUSE10
>     PAUSE10
>     PAUSE10
> .endm
>
> //**********FIFO ROUTINES**************//
> //attention: all offsets (3rd argument) are reduced by one, as ADC_ADDR 
> was increased by one before
>
> //Read a value from the FIFO0 buffer of the ADC
> .macro  READFIFO
> .mparam dst
>     LBBO    dst,ADC_ADDR,0xFF,4
> .endm
>
> //Read a how many values are stored in the FIFO0 register of the ADC
> .macro  READFIFOCNT
> .mparam dst
>     LBBO    dst,ADC_ADDR,0xE3,2
> .endm
>
> //Read the status register of the ADC IRQ
> .macro  READFIFOIRQ
> .mparam dst
>     LBBO    dst,ADC_ADDR,0x23,2
> .endm
>
> //Clear the stats register of the ADC IRQ
> .macro  CLEARFIFOIRQ
> .mparam dst
>     MOV     dst,0x0FFF
>     SBBO    dst,ADC_ADDR,0x27,2
>     READFIFOIRQ dst
> .endm
>
> //Trigger a new ADC single-shot measurement
> .macro ENABLESTEP1
>     //STEPENABLE:    
>     //enable only STEP1 a.k.a. bit 1
>     MOV ENABLESTEPBUFFER,0x02 
>     SBBO ENABLESTEPBUFFER,ADC_ADDR,0x53,1
> .endm
>
> //********* End of FIFO routines *******//
>
>
> Next file with executable code
>
>
> // prucode1.p
> // Code for PRU1
>
> .setcallreg r0.w2
> .origin 0
> .entrypoint START
>
> //This is the first instruction that will be executed. For convenience, 
> the START section appears only after several definitions
> FIRSTINSTRUCTION: 
>     JMP START
>
> //Many definitions: Register names, Constants, Macros etc.
> #include "prucode.hp"
>
> /////////////////////CALL routines////////////
>
> //empty FIFO0 buffer so that zero values are in the 'pipeline'
> EMPTYFIFOBUFFER:
>     //get IRQ status before emptying
>     READFIFOIRQ VALUE1.w0
>
>     EMPTYFIFOBUFFERLOOP:
>         //read a value
>         READFIFO VALUE0.w0
>         //check buffer count
>         READFIFOCNT VALUE0.w2
>         //read more values until the buffer is empty
>         QBNE EMPTYFIFOBUFFER,VALUE.w2,0x0000
>
>     //clear and read out the status of the buffer
>     CLEARFIFOIRQ VALUE1.w2
>     RET
>
> //Init the whole program
> INIT:
>     //global config settings    
>     LBCO    VALUE, CONST_PRUCFG, 4, 4
>     CLR     VALUE, VALUE, 4       // Clear SYSCFG[STANDBY_INIT] to enable 
> OCP master port
>     CLR        VALUE, VALUE, 3        // set no-standby mode
>     SET        VALUE, VALUE, 2        // set no-standby mode
>     CLR        VALUE, VALUE, 1        // enable no-idle mode
>     SET        VALUE, VALUE, 0        // enable no-idle mode
>     SBCO    VALUE, CONST_PRUCFG, 4, 4
>     
>     // Configure the programmable pointer registers
>     //Configs for PRU1 at offset 0x000024000, for PRU0 at offset 0x00022000
>     MOV     ADDR, 0x00024000  
>     //CONST_PRU01DRAM (C24) and CONST_PRU10DRAM (C25) offset (bits 11-8) 
> config with bits 0-7 resp. 16-23
>     MOV     VALUE, 0x00000000
>     SBBO    VALUE,ADDR,0x20,4
>     //CONST_PRUSHAREDRAM (C28) bits 23-8 are given by bits 15:0 of VALUE
>     MOV     VALUE, 0x00010000>>8
>     SBBO    VALUE,ADDR,0x28,4
>     //CONST_DDR (C31) bits 23-8 are given by bits 31:16 of VALUE
>     MOV     VALUE, 0x00000000
>     SBBO    VALUE,ADDR,0x2C,4
>
>     // Initialize Pru Ram to zero
>     MOV VALUE,0x00000000
>     FILLDRAM VALUE
>     FILLSHAREDRAM VALUE
>
>     RET
>     
> SETUPADC:
>     // SETUP ADDRESS REGISTERS
>     MOV ADC_ADDR,ADC_TSC
>     
>     //because Immediate value addressing only goes up to 255 and 
>     //because we need an offset of 256 for accessing the FIFO, increase 
> the base address by 1
>     //this means, that all other offsets need to be reduced by 1 in the 
> following w.r.t. their offsets from the TRM
>     ADD ADC_ADDR,ADC_ADDR,1
>     
>     //disable TSC_ADC_SS module,dont write channel id into FIFO 
>     //and disprotect step config registers        
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000004    //as above said already: disprotect and 
> disable...
>     SBBO VALUE,ADDR,0x40,4  //write value to CTRL register
>     
>     //ADC_CLKDIV
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000   //the 24MHz-clock rate is divided by VALUE+1 to 
> yield ADC_CLOCK 
>     SBBO VALUE,ADDR,0x4C,4 //important to write all 4 bytes even though 
> only the first 2 count - if this is not done, the change doesnt take effect 
> for some reason  
>     
>     //TS_CHARGE_STEPCONFIG
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000    //no unnecessary delay, do nothing here
>     SBBO VALUE,ADDR,0x5C,4   
>     
>     //TS_CHARGE_DELAY
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000001    //value must be greater than 0
>     SBBO VALUE,ADDR,0x60,4   
>     
>     //STEPCONFIG1: SW continuous and no averages
>     //bits 22-19: AINx; bit1-0 = 01 for continuous
>     //bits 4-2 averaging: 100=16avg,000no avg
>     MOV ADDR,ADC_TSC
>     //MOV VALUE,0x00080001 //continuous mode
>     MOV VALUE,0x00080000 //sw one-shot mode
>     SBBO VALUE,ADDR,0x64,4   
>     
>     //STEPDELAY1 - add highest two bytes any value if the sampling need to 
> be slowed down
>     //integrate signal at analog input over 1 analog sample cycles
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000    //bits 31-24: SampleDelay; bits 17-0: OpenDelay
>     SBBO VALUE,ADDR,0x68,4   //STEPDELAY1  
>
>     //for future implementations of averaging etc., we also configure 
> steps 2 and 3 although they are never used here
>     
>     //STEPCONFIG2: SW continuous and no averages
>     //bits 22-19: AINx; bit1-0 = 01 for continuous
>     //bits 4-2 averaging: 100=16avg,000no avg
>     MOV ADDR,ADC_TSC
>     //MOV VALUE,0x00080001 //continuous mode
>     MOV VALUE,0x00080000 //one-shot mode
>     SBBO VALUE,ADDR,0x6C,4   
>     
>     //STEPDELAY2
>     //integrate signal at analog input over 1 analog sample cycles
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000    //bits 31-24: SampleDelay; bits 17-0: OpenDelay
>     SBBO VALUE,ADDR,0x70,4   //STEPDELAY2  
>     
>     //STEPCONFIG3: SW continuous and no averages
>     //bits 22-19: AINx; bit1-0 = 01 for continuous
>     //bits 4-2 averaging: 100=16avg,000no avg
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00080001    
>     SBBO VALUE,ADDR,0x74,4   
>
>     //STEPDELAY3
>     //integrate signal at analog input over 1 analog sample cycles
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000  //bits 31-24: SampleDelay; bits 17-0: OpenDelay
>     SBBO VALUE,ADDR,0x78,4   //STEPDELAY2  
>     
>     //STEPENABLE:    
>     //enable only STEP1 a.k.a. bit 1
>     //here: disable all steps for now
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000 
>     SBBO VALUE,ADDR,0x54,4
>     
>     //FIFO0THRESHOLD
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x000000FF //bits 5:0  = Value-1 for FIFO Threshold 
> interrupt generation
>     SBBO VALUE,ADDR,0xE8,4
>     
>     //SYSCONFIG
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000000 //bits 3:2  00=force idle, 01=no idle, 10=smart 
> idle, 11=smart idle+wakeup
>     SBBO VALUE,ADDR,0x10,4
>     
>     //enable TSC_ADC_SS module,dont write channel id 
>     //and write-protect step config registers
>     MOV ADDR,ADC_TSC
>     MOV VALUE,0x00000001     
>     SBBO VALUE,ADDR,0x40,4
>
>     RET
>
> START:
>     //Zero all registers to avoid ambiguity
>     ZERO &r0,124
>     //Initialise memory and registers
>     CALL INIT
>     
>     //Setup ADC
>     CALL SETUPADC
>     
>     //empty FIFO0 buffer in case it is not clean
>     CALL EMPTYFIFOBUFFER
>     //re-zero the buffer variables used by EMPTYFIFOBUFFER
>     MOV VALUE0,0x00000000
>     MOV VALUE1,0x00000000
>     
> MAINLOOP:
>     //ask for a new value from the ADC, whose preparation takes about 190 
> clock cycles 
>     //(should be only 125 cycles (625ns) and once this worked, but 
> recently there are problems. Maybe due to readout latency from FIFO?)
>     ENABLESTEP1
>     
>     //wait the required amount of time, and a bit more to make sure we 
> dont read a value when there is none
>     PAUSE100
>     PAUSE100
>
>     //do the same as in PID-Loop without sending Enablestep
>     //retrieve sampled analog data
>     READFIFO X0
>     //now we have the last adc sampling value (from AIN1) in the register 
> X0 and can write it to DDR memory or do whatever else we want
>    //........
>
>     JMP MAINLOOP
>
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to