| Author |
Message |
|
|
Posted: Jan 13, 2012 - 07:14 PM |
|

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);
.
.
.
|
|
|
| |
|
|
|
|
|
Posted: Jan 13, 2012 - 09:31 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 13, 2012 - 10:02 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jan 13, 2012 - 11:03 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 14, 2012 - 12:28 AM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2012 - 10:42 AM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2012 - 10:43 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 17, 2012 - 08:46 AM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jan 19, 2012 - 03:47 PM |
|

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
|
|
|
| |
|
|
|
|
|
Posted: Jan 20, 2012 - 04:54 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 20, 2012 - 07:33 PM |
|

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)
{
}
}
|
|
|
| |
|
|
|
|
|
Posted: Jan 20, 2012 - 08:36 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jan 21, 2012 - 02:04 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 21, 2012 - 02:53 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jan 21, 2012 - 05:28 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jan 22, 2012 - 12:27 AM |
|

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] | ..... |
|
|
| |
|
|
|
|
|
Posted: Jan 30, 2012 - 09:47 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Feb 04, 2012 - 02:54 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Feb 06, 2012 - 07:16 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Feb 07, 2012 - 05:30 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Feb 10, 2012 - 03:19 PM |
|

Joined: May 21, 2009
Posts: 34
|
|
This time i think i found the problem
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. |
|
|
| |
|
|
|
|
|