Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
nutron
PostPosted: Jan 13, 2012 - 07:14 PM
Rookie


Joined: May 21, 2009
Posts: 34


I am trying to use PDCA and SSC in order to have an uninterrupted flow of data on the SSC bus.

The data length of the SSC word is supposed to be
32 bits.

What happens is that it sends the first element of the array and then it sends a gap of zeros and then again the first element.

the sequence looks like this :

0xFFAA0000|0x00|0xFFAA0000|0x00|......


how can i avoid the zero gap ?





Code:


int32_t buffer[0];

buffer[0]=0b11111111101010100000000000000000; //0xFFAA0000

.
.
.


__attribute__((__interrupt__))
static void pdca_int_handler(void)
{
   pdca_reload_channel(0, (void *)buffer,1);

}

.
.
.

static const pdca_channel_options_t PDCA_OPTIONS =
   {
     .addr = (void *)buffer,
     .pid = AVR32_PDCA_PID_SSC_TX,
     .size = 1,
     .r_addr = NULL,
     .r_size = 0,
     .transfer_size = PDCA_TRANSFER_SIZE_WORD
   };
.
.
.
pdca_init_channel(0, &PDCA_OPTIONS);
Disable_global_interrupt();
INTC_init_interrupts();
INTC_register_interrupt((__int_handler) &pdca_int_handler, AVR32_PDCA_IRQ_0, AVR32_INTC_INT0);
Enable_global_interrupt();

pdca_enable_interrupt_reload_counter_zero(0);
pdca_enable(0);
.
.
.


 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 13, 2012 - 09:31 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Are you sure the interface between Codec and SSC is ok? The codecs often has 64 clock periodes for each sample, but using a common frame sync for the two stereo channels. Try generating a frame sync every 64 data clock (but length of frame pulse = 32 clocks), and use trigger on every frame sync edge (0x07).

Program the Codec for left justified output, and program the SSC to take one word of ie 16 or 18 bit for each transfer.

If you use 16 bit transfer, the PDCA can use half word for each transfer, but 18 bits require word transfer for the PDCA.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 13, 2012 - 10:02 PM
Rookie


Joined: May 21, 2009
Posts: 34


The codec i'm using receives the left and right channel in a single sync frame , so every 32bit a frame sync pulse. (DSP-Frame)

like this...

data :_______LLLRRR_LLLRRR_LLLRRR
bit clock :_||||||||||||||||||||||
frame sync :F______F______F______F



I am not concerned about the the communication between the MCU and the codec ,that part works fine.

when i use

ssc_i2s_transfer(ssc,buffer);

in the main loop i get a constant stream of data on the SSC bus without interruption , even when i use interrupts with the SSC i get a constant stream.

but with PDCA i get a result that looks like this...

data :_______LLLRRR_000000_LLLRRR
bit clock :_||||||||||||||||||||||
frame sync :F______F______F______F

as you can see there is a zero transfer inserted between each real data transfer
 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 13, 2012 - 11:03 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Ok. What I experienced with pcm3060 from TI (which use I2S) was that there is some "space" (dead time) in the timing diagrams for the audio interface, and if I remember right, the codec required 64 clocks because it supports more than 16 bits for each channel. The codec was set up to use left justified format.

Perhaps PDCA makes things go so fast that you miss samples. Using interrupts and PIO slows things down so the codec may work because of the delays.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 14, 2012 - 12:28 AM
Rookie


Joined: May 21, 2009
Posts: 34


i know what you talking about when you say some deadtime.

But that's not the case , in my case.
my frames have no deadtime the 2 16Bit fit perfect in the frame.

If you take a look at the code i posted , i don't read from the codec i write data to it and on the scope it looks like the MCU is inserting dead frames after each successful transfer.

It must have something to do with the point where it reloads the data , i guess.... , i don't know yet.
 
 View user's profile Send private message  
Reply with quote Back to top
Matthieu_
PostPosted: Jan 16, 2012 - 10:42 AM
Rookie


Joined: Mar 24, 2011
Posts: 34


Hi Nutron,

To start:what's your device ?
i don't understand how it can send several time your buffer.
From my understand, it should send it only one time.

From Atmel UC3C datasheet:
Quote:

TCRR:
Reload value for the TCR register. When TCR reaches zero, it will be reloaded with TCRV if TCRV has a positive value. If TCRV
is zero, no more transfers will be performed for the channel. When TCR is reloaded, the TCRR register is cleared

From your code TCRV is 0, so i think you should not have interrupt when TCRR=0,as TCR will no be reloaded.

For your test ( to skip the 0x00 data transfer),i suggest you to use :

Code:

static const pdca_channel_options_t PDCA_OPTIONS =
   {
     .addr = (void *)buffer,
     .pid = AVR32_PDCA_PID_SSC_TX,
     .size = 1,
     .r_addr = (void *)buffer,
     .r_size = 1,
     .transfer_size = PDCA_TRANSFER_SIZE_WORD
   };

and enable Ring Mode
Code:

//   Enable Ring Mode
   Pdca_Channel_t_DACx_Chx->mr =  Pdca_Channel_t_DACx_Chx->mr | AVR32_PDCA_RING_MASK   ;

with these settings , no needs to use interrupts for pdca reloads.

for you application,you may use 2 buffers
Code:

static const pdca_channel_options_t PDCA_OPTIONS =
   {
     .addr = (void *)buffer_1,
     .pid = AVR32_PDCA_PID_SSC_TX,
     .size = buffer_1_size,
     .r_addr = (void *)buffer_2,
     .r_size = buffer_2_size,
     .transfer_size = PDCA_TRANSFER_SIZE_WORD
   };


in this case, enable interrupt on TCRR=0.
in this ISR, reload TCRR and MARR with new counter value and buffer address.

Regards,
Matthieu
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 16, 2012 - 10:43 PM
Rookie


Joined: May 21, 2009
Posts: 34


Hello Matthieu.

Thank you for your reply.

i am using a UC3B064 MCU.

I tried the suggestions you mentioned , but no success.

even if i use a bigger array lets say with 5 records it is still the same problem.

between each record from the array there is always a 0x00 packet inserted.

I am not so sure about the Pdca_Channel_t_DACx_Chx ?

is that the pdca channel used for the SSC or is that the DMA channel used between the DAC and the PDCA in the UC3A series MCUs?

the idea with the 2 buffers did nothing either ,i see only what's in buffer_1.

i also played with the SSC interrupts and so far only the TXBUFE interrupt of the SSC is triggering any transfers using the PDCA.
 
 View user's profile Send private message  
Reply with quote Back to top
Matthieu_
PostPosted: Jan 17, 2012 - 08:46 AM
Rookie


Joined: Mar 24, 2011
Posts: 34


Quote:
I am not so sure about the Pdca_Channel_t_DACx_Chx ?

Sorry, i copy a piece of my code.
Pdca_Channel_t_DACx_Chx is a pointer on used PDCA channel (avr32_pdca_channel_t)
value is given by function:
avr32_pdca_channel_t *pdca_get_handler(unsigned int pdca_ch_number);

you should use:
Code:
// Init PDCA channel with the pdca_options.
   pdca_init_channel(0, &Pdca_Option); // init PDCA channel with options.

   //   Get PDCA Handler
   Pdca_Channel_t_Handler_= pdca_get_handler(0);
   //   Enable Ring Mode
   Pdca_Channel_t_Handler->mr =  Pdca_Channel_t_Handler->mr | AVR32_PDCA_RING_MASK   ;


In TCMR, what is the value of:
PERIOD
In TFMR, what are the value of:
- DATLEN?
- DTDEF?
- DATNB?

Regards,
Matthieu
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 19, 2012 - 03:47 PM
Rookie


Joined: May 21, 2009
Posts: 34


PERIOD = 15
DATLEN = 31
DTDEF = 0
DATNB = 0


Here is my SSC setup


Code:

   //CLK DIV inactive

   //               BCKL freq calculation for PCM3001
   //
   //                          MCKL
   // freq BCKL = -------------------------------
   //                          MCKL
   //               --------------------------
   //             sampling freq  x Nr DATA bits


   // bitclock frequency = MCUMCK / (2 x DIV)

   ssc->cmr  = 0b000000000000000000000000000001000; // 8



      /*PERIOD: Transmit Period Divider Selection  : 00001111
        *STTDLY: Transmit Start Delay               : 00000000
        *dummy                               : 0000
        *START: Transmit Start Selection          : 0011
        *Transmit Clock Gating Selection          : 00
        *CKI: Transmit Clock Inversion             : 1
        *CKO: Transmit Clock Output Mode Selection  : 000
        *CKS: Transmit Clock Selection             : 10
        */
           //ssc->rcmr =0b00000000000000000000010000000100;
           //----------|-------|-------|-------|-------|
          ssc->tcmr =0b00001111000111110000001000000100;

          //ssc->rcmr =0b00001111000111110000000100000101;

       /*
       TFMR

       FSLENHI: Transmit Frame Sync Length High part   0000

       dummy                                           000

       FSEDGE: Frame Sync Edge Detection               0
       FSDEN: Frame Sync Data Enable                   0
       FSOS: Transmit Frame Sync Output Selection      010
       FSLEN: Transmit Frame Sync Length               0000

       dummy                                           0000

       DATNB: Data Number per frame                    0000
       MSBF: Most Significant Bit First                1

       dummy                                           0

       DATDEF: Data Default Value                       0
       DATLEN: Data Length                             01111
       */


         //ssc->rfmr = 0b00000000000000000000000010011111;
        ssc->tfmr = 0b00000000001000000000000010011111;
         /*
          *Bit 0 : RXEN : 1
          *Bit 8 : TXEN : 1
          */
        ssc->cr = 0b00000000000000000000000100000000; //EN RX/TX

 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 20, 2012 - 04:54 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Is the part old? Some of the very early "engineering sample" parts had errors. But (most of) the errors are covered in the datasheet errata. I think the UC3A was first (2007), then came the UC3B.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 20, 2012 - 07:33 PM
Rookie


Joined: May 21, 2009
Posts: 34


I have an F and an I version of that chip and they both do the same.

i even updated the framework , tool chain and compiler to the latest version.

can you guys try this code and see if your results match with mine ?


i wonder if it might have something to do with

int32_t buffer[];

i actualy dont need an array for what i want to do , but i don't know any other way to use a pointer to satisfy the compiler either.



Code:

#include <avr32/io.h>
#include <string.h>
#include "gpio.h"
#include "compiler.h"
#include "preprocessor.h"
#include "pm.h"
#include "intc.h"
#include "flashc.h"
#include "pdca.h"
#include "ssc_i2s.h"


int32_t buffer[];



volatile avr32_pm_t *pm = &AVR32_PM;
volatile avr32_ssc_t *ssc = &AVR32_SSC;



__attribute__((__interrupt__))
static void pdca_int_handler(void)
{
   pdca_load_channel(0, (void *)buffer,1);

}



int main(void)
{


static const gpio_map_t GPIO_MAP_SSC =
{
  {AVR32_SSC_TX_CLOCK_0_PIN ,   AVR32_SSC_TX_CLOCK_0_FUNCTION},
  {AVR32_SSC_TX_DATA_0_PIN ,   AVR32_SSC_TX_DATA_0_FUNCTION},
  {AVR32_SSC_TX_FRAME_SYNC_0_PIN ,   AVR32_SSC_TX_FRAME_SYNC_0_FUNCTION},
  {AVR32_SSC_RX_DATA_0_PIN ,   AVR32_SSC_RX_DATA_0_FUNCTION}
  //{AVR32_SSC_RX_FRAME_SYNC_0_PIN ,   AVR32_SSC_RX_FRAME_SYNC_0_FUNCTION}
};

static const gpio_map_t GPIO_MAP_PM =
{
{AVR32_PM_GCLK_0_PIN ,   AVR32_PM_GCLK_0_FUNCTION},
};


pm_enable_osc0_crystal(pm,12288000); //crystal mode
pm_enable_clk0(pm,4096);

//pm_enable_osc0_ext_clock(pm); //ext clock mode , not crystal mode
//pm_enable_clk0_no_wait(pm,3);

pm_pll_setup(pm,0,7,1,0,16); // 98.3 Mhz at 12.288MHz input
pm_pll_set_option(pm,0,1,1,1); //pll output freq 98.3MHz/2
pm_pll_enable(pm,0);
pm_wait_for_pll0_locked(pm);
pm_switch_to_clock(pm, AVR32_PM_MCSEL_PLL0);
pm_cksel(pm,1,0,0,0,0,0); // devide PBA / 2 = 24.5 MHZ , MAXIMUM bus frequency 30MHz
flashc_set_wait_state(1);  // one wait state because CPU clocked higher than 30MHz


pm_gc_setup(pm,0,1,0,1,1); //generic clock 12Mhz
pm_gc_enable(pm,0) ;



static const pdca_channel_options_t PDCA_OPTIONS =
   {
     .addr = (void *)buffer,              // memory address
     .pid = AVR32_PDCA_PID_SSC_TX,  // select peripheral - data are transmit on USART TX line.
     .size = 1,                        // transfer counter
     .r_addr = (void *)buffer,                           // next memory address
     .r_size = 1,                              // next transfer counter
     .transfer_size = PDCA_TRANSFER_SIZE_WORD  // select size of the transfer
   };

buffer[0]=0b11111111101010101010101010101010;


gpio_enable_module(GPIO_MAP_PM, sizeof(GPIO_MAP_PM) / sizeof(GPIO_MAP_PM[0]));
gpio_enable_module(GPIO_MAP_SSC, sizeof(GPIO_MAP_SSC) / sizeof(GPIO_MAP_SSC[0]));



pdca_init_channel(0, &PDCA_OPTIONS);
ssc_i2s_init(ssc);
ini_codec(ssc);


Disable_global_interrupt();
INTC_init_interrupts();

INTC_register_interrupt((__int_handler) &pdca_int_handler, AVR32_PDCA_IRQ_0, AVR32_INTC_INT0);

Enable_global_interrupt();



//pdca_enable_interrupt_transfer_complete(0);
pdca_enable_interrupt_reload_counter_zero(0);

pdca_enable(0);


   while(1==1)
   {
      
   }



}


 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 20, 2012 - 08:36 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Try init the "int32_t buffer[];" with a fixed size.

Another "problem" with UC3 compared to the AP7000 is that words/halfwords cannot be located to byte or halfword aligned address (the buffer starts at ie 0x01 -> exception when accessing it), but the compiler should take care of array alignment.

Try printing the buffer address to check it.

I don't use the framework, but here is the order of function calls I use with a working PCM3060 codec DAC:

init:
-reset SSC (SWRST bit)
-init SSC (values into registers, but not TX enable bit)
-init PDCA but no enable
-register PDCA interrupt (reload)
-enable global interrupts

start playback:
-if DAC is slave init and enable it here
-init memory address and enable PDCA
-enable SSC TX
-if DAC is master enable it here
 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 21, 2012 - 02:04 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Code:
static const pdca_channel_options_t PDCA_OPTIONS =
    {
      .addr = (void *)buffer,              // memory address
      .pid = AVR32_PDCA_PID_SSC_TX,  // select peripheral - data are transmit on USART TX line.
      .size = 1,                        // transfer counter
      .r_addr = (void *)buffer,                           // next memory address
      .r_size = 1,                              // next transfer counter
      .transfer_size = PDCA_TRANSFER_SIZE_WORD  // select size of the transfer
    };


Is the size of the buffer only one word?

If you want to treat each sample individually (no buffer), it is easier to skip the PDCA altogether and poll the SSC status register instead. Or use an SSC interrupt.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 21, 2012 - 02:53 PM
Rookie


Joined: May 21, 2009
Posts: 34


Yes it is supposed to be only one word.

i just wanted to take advantage of bypassing the CPU to access the SSC.

but it still does not the solve the problem . i tried it even with a buffer/array of 5 words and it was still inserting a zero gap between each transmit.

i used to do it with interrupt or just in the main loop and it was fine i had steady stream without any zero gap.

i did the whole PDCA thing once with the USART reading from a 32bit word/buffer and sending out 8bits each transfer and it worked fine , i had a nice steady stream without any gaps , don't know why it won't do it on the SSC.

maybe i need a 64 bit buffer ? i don't think you can do that on the UC3B.
 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Jan 21, 2012 - 05:28 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

I don't think the data type of the array is important for the PDCA, it only need the base address, transfer size and number of transfers.

But the data type is of course important for the software part of the buffer. Try increasing the buffer to 2 and add this line to the init:

buffer[0]=0b11111111101010101010101010101010;
buffer[1]=0b11111111101010101010101010101010;

But using PDCA with such small buffers is probably not saving any CPU cycles compared to polling because of the interrupt handler that runs for almost each sample.

Are you ysing the reaload feature (double buffer) the reload address could/should (i am not sure) be an alternate buffer and not the same one each time. So you could try two buffers, each with size 1 or 2
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 22, 2012 - 12:27 AM
Rookie


Joined: May 21, 2009
Posts: 34


you got a point with being near nonsense using such a small buffer , since after each transmit an interrupt is triggered.

i already tried using a bigger buffer , up to 5 records but i still had the same issue after each transfer there was a zero transfer.

like this...

buffer[0] | 0x00000000 | buffer [1] | 0x00000000 | .....


in theory it should be like this...

buffer[0] | buffer [1] | buffer [0] | buffer [1] | .....
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Jan 30, 2012 - 09:47 PM
Rookie


Joined: May 21, 2009
Posts: 34


I think i know what caused the data gap now.

It seems like the period length value in the TCMR register needs to be longer than the actual data one wants to transmit.

I wrote a test app where i used the ssc_i2s_transfer() function and had the same issue.

So a played around with the period length value in the TCMR register and discovered something odd.

I used to have 15 as period length value in the TCMR register which is equal to 32 according to the formula in the data sheet 2 x (PERIOD+1) .

I changed it to 16 which equals 34 according to the formula 2 x (PERIOD+1).

I just wonder why the period length value in the TCMR register has to be bigger than the actual data word in order to avoid data gaps.
 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Feb 04, 2012 - 02:54 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

Thanks for posting the solution. It could have something to do with the CODEC, giving it some time to put the data into the register or something like that.

What is the ratio between the sample clock and SSC data clock?

Edit: the CODEC is of course not the problem, the DAC data from SSC master should be available even without the CODEC present. But it could be that the SSC shift register + PDCA in the MCU need some time glitch to do the data register transfers.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Feb 06, 2012 - 07:16 PM
Rookie


Joined: May 21, 2009
Posts: 34


I programmed it in a way that the codec is in full dependency to the MCU , all clocks are provided by the MCU , the MCU is the master.

The solution i posted works , but it has a drawback.

At the end of 32 bit word transmited by the MCU is a gap 2 bitclock cycles before the FSYNC pulse.

the available options for the TCMR are : 14 , 15 and 16.

14 would result in 30 bitclock cycles which would chop off 2 bits

15 would result in 32 bitclock cycles which would be perfect , but for some reason it causes that datgap.
It's like there is 1Bit over that the MCU is trying to transmit.

16 would result in 34 bitclock cycles which will add 2 additional bits to the end of the 32Bit word.


I wonder if 32Bits/cyle of data is a borderline case that is not programmed correctly in the toolchain.
 
 View user's profile Send private message  
Reply with quote Back to top
Heihopp
PostPosted: Feb 07, 2012 - 05:30 PM
Hangaround


Joined: Jun 04, 2007
Posts: 490
Location: Norway

You could try increasing the bitclock, for example to twice the speed, then generate framesync every 64 clock and keep the word length. Then the MCU would have plenty of time to "recover" from each transfer.

Of course this require that the CODEC/DAC support different clocks for data and sampling, but many of these supports this.
 
 View user's profile Send private message  
Reply with quote Back to top
nutron
PostPosted: Feb 10, 2012 - 03:19 PM
Rookie


Joined: May 21, 2009
Posts: 34


This time i think i found the problem Laughing

It was my own mistake.

Code:


      /*PERIOD: Transmit Period Divider Selection  : 00001111
        *STTDLY: Transmit Start Delay               : 00000000
        *dummy                               : 0000
        *START: Transmit Start Selection          : 0011
        *Transmit Clock Gating Selection          : 00
        *CKI: Transmit Clock Inversion             : 1
        *CKO: Transmit Clock Output Mode Selection  : 000
        *CKS: Transmit Clock Selection             : 10
        */
           //ssc->rcmr =0b00000000000000000000010000000100;
           //----------|-------|-------|-------|-------|
          ssc->tcmr =0b00001111000111110000001000000100;



When you look at the STTDLY value , it is 31.
no wonder i had always one empty frame.

Ouch , that's dumm.



i reduced it to the STTDLY value to zero and the empty frame was gone and everything works as intended.


but it was a good exercise.


Thanks everybody for your great support and suggestions.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits