Frame-Sync synchronous serial communication is the
perfect protocol for transmitting data of multiple channels.
Here is how a typical TDM (time-division multiplexed) Frame-Sync
synchronous serial data communication should work:

With these features, this protocol will never result in channel rotation
even when there are glitches on the lines
Hardware
To demonstrate this problem, we need two EVK1100s and
designate one as transmitter and the other as receiver.


Make the following wiring connections:
-
Transmitter's PA16 to Receiver's PA17: Serial Data
Out/In
-
Transmitter's PA15 to Receiver's PA18: Serial Clock
-
Transmitter's PA14 to Receiver's PA19: Serial Data
Frame Sync
Software implementation for the
transmitter
ssc->tcmr = 0 << AVR32_SSC_TCMR_CKS_OFFSET |
1 << AVR32_SSC_TCMR_CKO_OFFSET |
1 << AVR32_SSC_TCMR_CKI_OFFSET |
0 << AVR32_SSC_TCMR_CKG_OFFSET |
5 << AVR32_SSC_TCMR_START_OFFSET |
1 << AVR32_SSC_TCMR_STTDLY_OFFSET |
255 << AVR32_SSC_TCMR_PERIOD_OFFSET;
ssc->tfmr = (24 - 1) << AVR32_SSC_TFMR_DATLEN_OFFSET |
1 << AVR32_SSC_TFMR_DATDEF_OFFSET |
1 << AVR32_SSC_TFMR_MSBF_OFFSET |
3 << AVR32_SSC_TFMR_DATNB_OFFSET |
(((0) << AVR32_SSC_TFMR_FSLEN_OFFSET) & AVR32_SSC_TFMR_FSLEN_MASK) |
2 << AVR32_SSC_TFMR_FSOS_OFFSET |
1 << AVR32_SSC_TFMR_FSDEN_OFFSET |
0 << AVR32_SSC_TFMR_FSEDGE_OFFSET |
((0) >> AVR32_SSC_TFMR_FSLEN_SIZE) << AVR32_SSC_TFMR_FSLENHI_OFFSET;
For detail settings/timing, please refer to the following screen
captures from the logic analyzer
void out_overrun_callback(void)
{
ssc_pdc_output(buffer_out,(SAMPLE_COUNT));
}
...
int main(void)
{
...
for (i=0; i<SAMPLE_COUNT; ){
buffer_out[i++]=0x11111111;
buffer_out[i++]=0xFFFFFFFF;
buffer_out[i++]=0xFFFFFFFF;
buffer_out[i++]=0xFFFFFFFF;
}
.....
// Start SSC
ssc_pdc_start(DEFAULT_SAMPLE_RATE_HZ,
4,
24,
SAMPLE_COUNT,
FALSE,
&out_overrun_callback,
&in_underrun_callback,
FOSC0*4); //48Mhz
ssc_pdc_output(buffer_out,(SAMPLE_COUNT));
while (1);
}
As long as you don't write your codes to run into the problem in AVR's SSC output unit, you will have a good data
stream.

Software Implementation in the Receiver
(For detail settings, please refer to the screen captures of the logic
analyzer)
ssc->rcmr = 2 <<
AVR32_SSC_RCMR_CKS_OFFSET |
0 << AVR32_SSC_RCMR_CKO_OFFSET |
1 << AVR32_SSC_RCMR_CKI_OFFSET |
0 << AVR32_SSC_RCMR_CKG_OFFSET |
4 << AVR32_SSC_RCMR_START_OFFSET |
0 << AVR32_SSC_RCMR_STTDLY_OFFSET |
0 << AVR32_SSC_RCMR_PERIOD_OFFSET;
ssc->rfmr = (data_bit_res
- 1) << AVR32_SSC_RFMR_DATLEN_OFFSET |
1 << AVR32_SSC_RFMR_MSBF_OFFSET |
3 << AVR32_SSC_RFMR_DATNB_OFFSET |
(((0) << AVR32_SSC_RFMR_FSLEN_OFFSET) &
AVR32_SSC_RFMR_FSLEN_MASK) |
0 << AVR32_SSC_RFMR_FSOS_OFFSET |
1 << AVR32_SSC_RFMR_FSEDGE_OFFSET |
0 << AVR32_SSC_RFMR_FSLENHI_OFFSET;
void in_underrun_callback(void)
{
rdone=1;
}
int main(void)
{
....
ssc_pdc_start(DEFAULT_SAMPLE_RATE_HZ,
4,
24,
SAMPLE_COUNT,
FALSE,
&out_overrun_callback,
&in_underrun_callback,
FOSC0*4); //48Mhz
myrepeat:
ssc_pdc_input(buffer_in,(SAMPLE_COUNT));
while (rdone==0){
print_dbg(".");
}
print_dbg("\n.............\n");
for (i=0; i<80; ){
print_dbg_hex(buffer_in[i++]);
print_dbg(" ");
print_dbg_hex(buffer_in[i++]);
print_dbg(" ");
print_dbg_hex(buffer_in[i++]);
print_dbg(" ");
print_dbg_hex(buffer_in[i++]);
print_dbg("\n");
}
goto myrepeat;
This will receive a batch of data, print them out and
reinitialize SSC/DMA for the next round
Result:
We run into the channel
rotation business. Instead of getting 00111111 as the first channel, it
can be anywhere depending sessions
.............
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
.............
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
00FFFFFF 00FFFFFF 00111111 00FFFFFF
.............
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
00FFFFFF 00111111 00FFFFFF 00FFFFFF
Fix it
Thanks to the help from Heihopp of AVR Freak forum!
The problem is ssc_pdc_start and ssc_pdc_input from the
Atmel example programs have a race condition. Tthe fix is to move the start
of SSC to after the start of PDAC by commenting out by commenting out ssc->cr
= AVR32_SSC_CR_RXEN_MASK in ssc_pdc_start and adding ssc->cr =
AVR32_SSC_CR_RXEN_MASK to the end of ssc_pdc_input