XMC4500 - USIC SSC Slave + SCLK generation [Errata USIC_AI.010]

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hi all,

at the IKOM fair in Munich I was given a XMC4500 Relax Lite Kit (thank you for that!) and started playing around with it (step code AB).

My first tiny project idea is a simple 8 color VGA driver using the USIC SSC channel in quad mode. Originally I wanted to use the channel in master in mode and the slave select output signal as active low HSYNC which gives me the possibility to use the built in slave delay capabilities for a very easy and precise HSYNC timing.
In prinicple, this was working quite well, except for the 64bit frame length limitation in quad SSC mode as described in "XMC4500 Errata Sheet for Steps ES-AB, AB", V 1.3, "USIC_AI.010:
Minimum and maximum supported word and frame length in multi-IO SSC modes".

I tried the suggested work around (disable PCR.MSLSEN, drive slave select via GPIO), moving HSYNC from slave select to D[3], but now, no data gets shifted out at all. After writing data to TBUF (or the FIFO), TCSR.TDV never gets cleared, no data is sent and the FIFO just runs full. Besides the exact workaround suggested in the Errata, I also tried to tie input stage DX2 to always 1 to always be selected or set SCTR.TRM = 0b11 to just ignore the slave select and always be active but none is working.

With my oscilloscope I can see, that after disabling PCR.MSLSEN, no SCLK is output. Therefore I also tried to use the feedback input path of DX1 to fetch to SCLKOUT signal generated by the baud rate generator together with INSW=1 instead of being controlled by the protocol pre-processor. But still no clock is present.

Now I assume, that when running in slave mode, either the fractional divider or the baud rate generator are not operational and the suggested workaround is not possible... or that I did something wrong (easier to fix 😉 )

Here is my code. First the "working" one with MSLSEN=1 (please note that A) the main loop does not really fit to the init() anymore since the black areas are now in the bit stream AND in the inter frame delay, B) I'm planning to fill the FIFO interrupt driven later on instead of having a blocking loop, C) due to the frame length limitation there is a frame end every 16 pixel and D) currently I have no VSYNC... but that's all independent on the problem):

#include 		//SFR declarations of the selected device

void init();

#define WAIT_FIFO_READY while((USIC0_CH0->TRBSR & USIC_CH_TRBSR_TFULL_Msk)) {}

int main(void)
{
int x, y, stat, size;

init();

while(1)
{
for(y = 0; y < 525; y++)
{
for(x = 0; x < 200; x++) // 640px visible + 16px FP + 96 px SP + 48px PB / 4 px per word
{

//WAIT_FIFO_READY;
do
{
stat = USIC0_CH0->TRBSR;
size = (stat & USIC_CH_TRBSR_TBFLVL_Msk) >> USIC_CH_TRBSR_TBFLVL_Pos;
}
while((stat & USIC_CH_TRBSR_TFULL_Msk));

if(x < 160)
{
// white with HSYNC = 1
USIC0_CH0->IN[15] = 0xffff;
}
else if(x < 164)
{
// Black with HSYNC = 1
USIC0_CH0->IN[15] = 0x8888;
}
else if(x < 188)
{
// Black with HSYNC = 0
USIC0_CH0->IN[15] = 0;
}
else
{
// Black with HSYNC = 1
USIC0_CH0->IN[15] = 0x8888;
}
}
}
}
return 0;
}

void init()
{
// Disable USIC reset
SCU_RESET->PRCLR0 = SCU_RESET_PRCLR0_USIC0RS_Msk;
__ISB();

// Enable USIC module
USIC0_CH0->KSCFG = USIC_CH_KSCFG_MODEN_Msk | USIC_CH_KSCFG_BPMODEN_Msk;
__ISB();

// Set up hardware port control
USIC0_CH0->CCR |= 0b11 << 6;
// Direction: output
USIC0_CH0->SCTR |= 1 << USIC_CH_SCTR_HPCDIR_Pos;

// Set up BAUD rate generator (25,2 MHz = 120 MHz * 430 / 1024 / 2)
// Fractional divider mode
USIC0_CH0->FDR = (0b10 << USIC_CH_FDR_DM_Pos)
// Step = 430
| (430 << USIC_CH_FDR_STEP_Pos);
// f_in = f_peripheral (120 MHz), f_sclk = f_out / 2
// f_CTQIN = f_sclk

// 4x gearing
USIC0_CH0->SCTR |= 0b11 << USIC_CH_SCTR_DSM_Pos;

// Configure FIFO buffer (full 64 entries for transmit channel 0)
// First disable FIFO
USIC0_CH0->TBCTR = 0;
__ISB();
// Data pointer = 0, LOF = 0, LIMIT = 1
USIC0_CH0->TBCTR = (1 << USIC_CH_TBCTR_LIMIT_Pos);
// Enable Standard Transfer Buffer Event Interrupt (later...)
// | (1 << USIC_CH_TBCTR_STBIEN_Pos);
__ISB();
// Size = 64 (activate)
USIC0_CH0->TBCTR |= (0b110 << USIC_CH_TBCTR_SIZE_Pos);

// Configure SPI like interface
// Enable Slave Select signals, Inter-word delay disabled
USIC0_CH0->PCR_SSCMode = (1 << USIC_CH_PCR_SSCMode_MSLSEN_Pos)
// Direct select mode (active high)
| (1 << USIC_CH_PCR_SSCMode_SELCTR_Pos)
// No automatic end of framed
| (1 << USIC_CH_PCR_SSCMode_FEM_Pos)
// channel 0 selected
| (1 << USIC_CH_PCR_SSCMode_SELO_Pos)
// Timing base for inter frame delay (HSYNC): f_sclk
| (0b10 << USIC_CH_PCR_SSCMode_CTQSEL1_Pos)
// Divided by 4
| (3 << USIC_CH_PCR_SSCMode_PCTQ1_Pos)
// 24 cycles (96 pixel HSYNC = 4 * 24 sclk cycles)
| (23 << USIC_CH_PCR_SSCMode_DCTQ1_Pos);

// Timing base for start / stop delay (front / back porch): f_sclk
USIC0_CH0->BRG = (0b10 << USIC_CH_BRG_CTQSEL_Pos)
// Divide by 1
| (0 << USIC_CH_BRG_DCTQ_Pos)
// 16 cycles
| (15 << USIC_CH_BRG_DCTQ_Pos);

USIC0_CH0->DX0CR = 1 << USIC_CH_DX0CR_INSW_Pos;
USIC0_CH0->DX1CR = 0;
USIC0_CH0->DX2CR = 0;
USIC0_CH0->DX3CR = 1 << USIC_CH_DX3CR_INSW_Pos;
USIC0_CH0->DX4CR = 1 << USIC_CH_DX4CR_INSW_Pos;
USIC0_CH0->DX5CR = 1 << USIC_CH_DX5CR_INSW_Pos;

// Transmission mode
USIC0_CH0->SCTR |= (0b01 << USIC_CH_SCTR_TRM_Pos)
// FIFO frame length control
| (63 << USIC_CH_SCTR_FLE_Pos);

// Word length control
USIC0_CH0->TCSR = (1 << USIC_CH_TCSR_WLEMD_Pos)
// Data single shot mode (required for FIFO operation)
| (1 << USIC_CH_TCSR_TDSSM_Pos)
// TBUF data enable
| (0b01 << USIC_CH_TCSR_TDEN_Pos)
| (1 << USIC_CH_TCSR_SOF_Pos);

__ISB();

// Enable SPI like interface
USIC0_CH0->CCR |= (1 << USIC_CH_CCR_MODE_Pos);
__ISB();

// Set up ports
// SCLK -> P0.8
PORT0->IOCR8 |= 0b10010 << PORT0_IOCR8_PC8_Pos;
// SELO0 -> P1.0
PORT1->IOCR0 |= 0b10010 << PORT1_IOCR0_PC0_Pos;
// D[3:0] -> P1.[2:5]
// Enable pull down
PORT1->IOCR4 |= 0b00001 << PORT1_IOCR4_PC5_Pos;
// Select hardware control
PORT1->HWSEL |= (0b01 << PORT1_HWSEL_HW2_Pos)
| (0b01 << PORT1_HWSEL_HW3_Pos)
| (0b01 << PORT1_HWSEL_HW4_Pos)
| (0b01 << PORT1_HWSEL_HW5_Pos);
}


Here the init() code with the workaround applied (now HSYNC is on D[3]):

void init()
{
// Disable USC reset
SCU_RESET->PRCLR0 = SCU_RESET_PRCLR0_USIC0RS_Msk;
__ISB();

// Enable USC module
USIC0_CH0->KSCFG = USIC_CH_KSCFG_MODEN_Msk | USIC_CH_KSCFG_BPMODEN_Msk;
__ISB();

// Set up hardware port control
USIC0_CH0->CCR |= 0b11 << 6;
// Direction: output
USIC0_CH0->SCTR |= 1 << USIC_CH_SCTR_HPCDIR_Pos;

// Set up BAUD rate generator (25,2 MHz = 120 MHz * 430 / 1024 / 2)
// Fractional divider mode
USIC0_CH0->FDR = (0b10 << USIC_CH_FDR_DM_Pos)
// Step = 430
| (430 << USIC_CH_FDR_STEP_Pos);
// f_in = f_peripheral (120 MHz), f_sclk = f_out / 2
// f_CTQIN = f_sclk
// Timing base for start / stop delay (front / back porch): f_sclk

// Also BRG = 0 does not work
USIC0_CH0->BRG = (0b10 << USIC_CH_BRG_CTQSEL_Pos)
// Divide by 1
| (0 << USIC_CH_BRG_DCTQ_Pos)
// 16 cycles
| (15 << USIC_CH_BRG_DCTQ_Pos);

// 4x gearing
USIC0_CH0->SCTR |= 0b11 << USIC_CH_SCTR_DSM_Pos;

// Configure FIFO buffer (full 64 entries for transmit channel 0)
// First disable FIFO
USIC0_CH0->TBCTR = 0;
__ISB();
// Data pointer = 0, LOF = 0, LIMIT = 1
USIC0_CH0->TBCTR = (1 << USIC_CH_TBCTR_LIMIT_Pos);
// Enable Standard Transfer Buffer Event Interrupt (later...)
// | (1 << USIC_CH_TBCTR_STBIEN_Pos);
__ISB();
// Size = 64 (activate)
USIC0_CH0->TBCTR |= (0b110 << USIC_CH_TBCTR_SIZE_Pos);

// Configure SPI like interface
// Enable Slave Select signals, Inter-word delay disabled

// Also PCR = 0 does not work
USIC0_CH0->PCR_SSCMode =
// Direct select mode (active high)
(1 << USIC_CH_PCR_SSCMode_SELCTR_Pos)
// No automatic end of framed
| (1 << USIC_CH_PCR_SSCMode_FEM_Pos)
// channel 0 selected
| (1 << USIC_CH_PCR_SSCMode_SELO_Pos)
// Timing base for inter frame delay (HSYNC): f_sclk
| (0b10 << USIC_CH_PCR_SSCMode_CTQSEL1_Pos)
// Divided by 4
| (3 << USIC_CH_PCR_SSCMode_PCTQ1_Pos)
// 24 cycles (96 pixel HSYNC = 4 * 24 sclk cycles)
| (23 << USIC_CH_PCR_SSCMode_DCTQ1_Pos);

USIC0_CH0->DX0CR = 1 << USIC_CH_DX0CR_INSW_Pos;
USIC0_CH0->DX1CR = 0b110 | (1 << USIC_CH_DX1CR_INSW_Pos); // also = 0; does not work
USIC0_CH0->DX2CR = 0b111 | (1 << USIC_CH_DX2CR_INSW_Pos); // also tying to a GPIO does not work
USIC0_CH0->DX3CR = 1 << USIC_CH_DX3CR_INSW_Pos;
USIC0_CH0->DX4CR = 1 << USIC_CH_DX4CR_INSW_Pos;
USIC0_CH0->DX5CR = 1 << USIC_CH_DX5CR_INSW_Pos;

// Transmission mode
USIC0_CH0->SCTR |= (0b01 << USIC_CH_SCTR_TRM_Pos)
// FIFO frame length control
| (63 << USIC_CH_SCTR_FLE_Pos)
| (15 << USIC_CH_SCTR_WLE_Pos);

// Word length control
USIC0_CH0->TCSR = (1 << USIC_CH_TCSR_WLEMD_Pos)
// Data single shot mode (required for FIFO operation)
| (1 << USIC_CH_TCSR_TDSSM_Pos)
// TBUF data enable
| (0b01 << USIC_CH_TCSR_TDEN_Pos);

__ISB();

// Enable SPI like interface
USIC0_CH0->CCR |= (1 << USIC_CH_CCR_MODE_Pos);
__ISB();

// Set up ports
PORT0->IOCR8 |= 0b10010 << PORT0_IOCR8_PC8_Pos;
PORT1->IOCR0 |= 0b10000 << PORT1_IOCR0_PC0_Pos;

// D[3:0] -> P1.[2:5]
// Select hardware control
PORT1->HWSEL |= (0b01 << PORT1_HWSEL_HW2_Pos)
| (0b01 << PORT1_HWSEL_HW3_Pos)
| (0b01 << PORT1_HWSEL_HW4_Pos)
| (0b01 << PORT1_HWSEL_HW5_Pos);
}


Thank you in advance!

Best regards,

Max
0 Likes
2 Replies
Not applicable
*push*

Any ideas anybody?

Thank you!
0 Likes
Not applicable
Hi,

My thought on this is that MSLSEN should not be cleared, MSLSEN=1 is defined as the setting for master mode. MSLSEN=0 sets up the channel as a SSC slave.

How about the following?
- keep MSLSEN = 1
- define SELO to a pin that is not connected
- drive the actual SELO pin through GPIO
- send the data as necessary

Regards,
T.O.M.
0 Likes