示例#1
0
void test_sgpio_sliceA_D(void)
{
	SGPIO_GPIO_OENREG = 0; // All inputs for the moment.

	// Disable all counters during configuration
	SGPIO_CTRL_ENABLE = 0;

	// Configure pin functions.
	configure_sgpio_pin_functions();

	/****************************************************/
	/* Enable SGPIO pin outputs. */
	/****************************************************/
	SGPIO_GPIO_OENREG =
        0xFFFF;           // data: output for SGPIO0 to SGPIO15

	/*******************************************************************************/
	/* SGPIO pin 0 outputs slice A bit 0. (see Table 212. Output pin multiplexing) */
	/*******************************************************************************/
	SGPIO_OUT_MUX_CFG(0) =
		(0L <<  4) |    // P_OE_CFG = X
		(0L <<  0);     // P_OUT_CFG = 0, dout_doutm1 (1-bit mode)

	// SGPIO pin 12 outputs slice D bit 0. (see Table 212. Output pin multiplexing)
	SGPIO_OUT_MUX_CFG(12) =
		(0L <<  4) |    // P_OE_CFG = X
		(0L <<  0);     // P_OUT_CFG = 0, dout_doutm1 (1-bit mode)

	/****************************************************/
	/* Slice A */
	/****************************************************/
	SGPIO_MUX_CFG(SGPIO_SLICE_A) = 
		(0L << 12) |    // CONCAT_ORDER = 0 (self-loop)
		(1L << 11) |    // CONCAT_ENABLE = 1 (concatenate data)
		(0L <<  9) |    // QUALIFIER_SLICE_MODE = X
		(0L <<  7) |    // QUALIFIER_PIN_MODE = X
		(0L <<  5) |    // QUALIFIER_MODE = 0 (enable)
		(0L <<  3) |    // CLK_SOURCE_SLICE_MODE = 0, slice D
		(0L <<  1) |    // CLK_SOURCE_PIN_MODE = X
		(0L <<  0);     // EXT_CLK_ENABLE = 0, internal clock signal (slice)

	SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
		(0L <<  8) |    // INV_QUALIFIER = 0 (use normal qualifier)
		(0L <<  6) |    // PARALLEL_MODE = 0 (shift 1 bit per clock)
		(0L <<  4) |    // DATA_CAPTURE_MODE = 0 (detect rising edge)
		(0L <<  3) |    // INV_OUT_CLK = 0 (normal clock)
		(0L <<  2) |    // CLKGEN_MODE = 0 (use clock from COUNTER)
		(0L <<  1) |    // CLK_CAPTURE_MODE = 0 (use rising clock edge)
		(0L <<  0);     // MATCH_MODE = 0 (do not match data)

	SGPIO_PRESET(SGPIO_SLICE_A) = 1;
	SGPIO_COUNT(SGPIO_SLICE_A) = 0;
	SGPIO_POS(SGPIO_SLICE_A) = (0x1FL << 8) | (0x1FL << 0);
	SGPIO_REG(SGPIO_SLICE_A) = 0xAAAAAAAA;     // Primary output data register
	SGPIO_REG_SS(SGPIO_SLICE_A) = 0xAAAAAAAA;  // Shadow output data register

	/****************************************************/
	/* Slice D (clock for Slice A) */
	/****************************************************/
	SGPIO_MUX_CFG(SGPIO_SLICE_D) = 
		(0L << 12) |    // CONCAT_ORDER = 0 (self-loop)
		(1L << 11) |    // CONCAT_ENABLE = 1 (concatenate data)
		(0L <<  9) |    // QUALIFIER_SLICE_MODE = X
		(0L <<  7) |    // QUALIFIER_PIN_MODE = X
		(0L <<  5) |    // QUALIFIER_MODE = 0 (enable)
		(0L <<  3) |    // CLK_SOURCE_SLICE_MODE = 0, slice D
		(0L <<  1) |    // CLK_SOURCE_PIN_MODE = X
		(0L <<  0);     // EXT_CLK_ENABLE = 0, internal clock signal (slice)

	SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_D) =
		(0L <<  8) |    // INV_QUALIFIER = 0 (use normal qualifier)
		(0L <<  6) |    // PARALLEL_MODE = 0 (shift 1 bit per clock)
		(0L <<  4) |    // DATA_CAPTURE_MODE = 0 (detect rising edge)
		(0L <<  3) |    // INV_OUT_CLK = 0 (normal clock)
		(0L <<  2) |    // CLKGEN_MODE = 0 (use clock from COUNTER)
		(0L <<  1) |    // CLK_CAPTURE_MODE = 0 (use rising clock edge)
		(0L <<  0);     // MATCH_MODE = 0 (do not match data)

	SGPIO_PRESET(SGPIO_SLICE_D) = 0;
	SGPIO_COUNT(SGPIO_SLICE_D) = 0;
	SGPIO_POS(SGPIO_SLICE_D) = (0x1FL << 8) | (0x1FL << 0);
	SGPIO_REG(SGPIO_SLICE_D) = 0xAAAAAAAA;     // Primary output data register
	SGPIO_REG_SS(SGPIO_SLICE_D) = 0xAAAAAAAA;  // Shadow output data register


	/****************************************************/
	/* Start SGPIO operation by enabling slice clocks. */
	/****************************************************/
	SGPIO_CTRL_ENABLE =
		(1L <<  SGPIO_SLICE_D) |    // Slice D
		(1L <<  SGPIO_SLICE_A);     // Slice A
	// Start SGPIO operation by enabling slice clocks.

	/* 
		Expected: 
		SGPIO12 = MCU Freq/2
		SGPIO0  = SGPIO12/2 MHz= 51MHz (SliceD/2)
	*/

}
示例#2
0
文件: sgpio.c 项目: epenelope/hackrf
/*
 SGPIO0 to 7 = DAC/ADC data bits 0 to 7 (Nota: DAC is 10bits but only bit9 to bit2 are used bit1 & 0 are forced to 0 by CPLD)
 ADC=> CLK x 2=CLKx2 with CLKx2(0)rising=D0Q, CLKx2(1)rising=D1I (corresponds to CLK(0)falling+tD0Q=>D0Q, CLK(1)rising+tDOI=>D1I, CLK(1)falling+tD0Q=>D1Q, CLK(1)rising+tDOI=>D2I ...)
 tDOI(CLK Rise to I-ADC Channel-I Output Data Valid)=7.4 to 9ns, tD0Q(CLK Fall to Q-ADC Channel-Q Output Data Valid)=6.9 to 9ns
 DAC=> CLK x 2=CLKx2 with CLKx2(0)rising=Q:N-2, CLKx2(1)rising=I:N-1(corresponds to CLK(0)rising=>Q:N-2, CLK(0)falling I:N-1, CLK(1)rising=>Q:N-1, CLK(1)falling I:N ...)
 tDSI(I-DAC Data to CLK Fall Setup Time)=min 10ns, tDSQ(Q-DAC Data to CLK Rise Setup Time)=min 10ns
 
 SGPIO8 Clock Input (External Clock)
 SGPIO9 Capture Input (Capture/ChipSelect, 1=Enable Capture, 0=Disable capture)
 SGPIO10 Disable Output (1/High=Disable codec data stream, 0/Low=Enable codec data stream)
 SGPIO11 Direction Output (1/High=TX mode LPC43xx=>CPLD=>DAC, 0/Low=RX mode LPC43xx<=CPLD<=ADC)
*/
void sgpio_configure(
	sgpio_config_t* const config,
	const sgpio_direction_t direction
) {
	// Disable all counters during configuration
	SGPIO_CTRL_ENABLE = 0;

    // Set SGPIO output values.
	const uint_fast8_t cpld_direction =
		(direction == SGPIO_DIRECTION_TX) ? 1 : 0;
    SGPIO_GPIO_OUTREG =
          (cpld_direction << 11) /* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode)*/
        | (1L << 10)	// disable codec data stream during configuration (Output SGPIO10 High)
		;

#ifdef RAD1O
	/* The data direction might have changed. Check if we need to
	 * adjust the q inversion. */
	update_q_invert(config);
#endif

	// Enable SGPIO pin outputs.
	const uint_fast16_t sgpio_gpio_data_direction =
		(direction == SGPIO_DIRECTION_TX)
		? (0xFF << 0)
		: (0x00 << 0);
	SGPIO_GPIO_OENREG =
	      (1L << 14)	// GPDMA burst request SGPIO14 active
	    | (1L << 11)	// direction output SGPIO11 active 
	    | (1L << 10)	// disable output SGPIO10 active
	    | (0L <<  9)	// capture input SGPIO9 (output i is tri-stated)
	    | (0L <<  8)	// clock input SGPIO8 (output i is tri-stated)
        | sgpio_gpio_data_direction // 0xFF=Output all SGPIO High(TX mode), 0x00=Output all SPGIO Low(RX mode)
		;

	SGPIO_OUT_MUX_CFG( 8) =		// SGPIO8: Input: clock
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */ 
		;
	SGPIO_OUT_MUX_CFG( 9) =		// SGPIO9: Input: qualifier
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */
		;
    SGPIO_OUT_MUX_CFG(10) =		// GPIO10: Output: disable
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) /* 0x4=gpio_out (level set by GPIO_OUTREG) */
		;
    SGPIO_OUT_MUX_CFG(11) =		// GPIO11: Output: direction
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) /* 0x4=gpio_out (level set by GPIO_OUTREG) */
		;
	SGPIO_OUT_MUX_CFG(14) =		// SGPIO14: Output: internal GPDMA burst request
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x4 dout_oem1 (1-bit mode) */
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */
		;

	const uint_fast8_t output_multiplexing_mode =
		config->slice_mode_multislice ? 11 : 9;
	/* SGPIO0 to SGPIO7 */
	for(uint_fast8_t i=0; i<8; i++) {
		// SGPIO pin 0 outputs slice A bit "i".
		SGPIO_OUT_MUX_CFG(i) =
		      SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		    | SGPIO_OUT_MUX_CFG_P_OUT_CFG(output_multiplexing_mode) /* 11/0xB=dout_doutm8c (8-bit mode 8c)(multislice L0/7, N0/7), 9=dout_doutm8a (8-bit mode 8a)(A0/7,B0/7) */
			;
	}

	const uint_fast8_t slice_indices[] = {
		SGPIO_SLICE_A,
		SGPIO_SLICE_I,
		SGPIO_SLICE_E,
		SGPIO_SLICE_J,
		SGPIO_SLICE_C,
		SGPIO_SLICE_K,
		SGPIO_SLICE_F,
		SGPIO_SLICE_L,
	};
	const uint_fast8_t slice_gpdma = SGPIO_SLICE_H;
	
	const uint_fast8_t pos = config->slice_mode_multislice ? 0x1f : 0x03;
	const bool single_slice = !config->slice_mode_multislice;
	const uint_fast8_t slice_count = config->slice_mode_multislice ? 8 : 1;
	const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 0;
	
	uint32_t slice_enable_mask = 0;
	/* Configure Slice A, I, E, J, C, K, F, L (sgpio_slice_mode_multislice mode) */
	for(uint_fast8_t i=0; i<slice_count; i++)
	{
		const uint_fast8_t slice_index = slice_indices[i];
		const bool input_slice = (i == 0) && (direction != SGPIO_DIRECTION_TX); /* Only for slice0/A and RX mode set input_slice to 1 */
		const uint_fast8_t concat_order = (input_slice || single_slice) ? 0 : 3; /* 0x0=Self-loop(slice0/A RX mode), 0x3=8 slices */
		const uint_fast8_t concat_enable = (input_slice || single_slice) ? 0 : 1; /* 0x0=External data pin(slice0/A RX mode), 0x1=Concatenate data */
		
		SGPIO_MUX_CFG(slice_index) =
		      SGPIO_MUX_CFG_CONCAT_ORDER(concat_order)
		    | SGPIO_MUX_CFG_CONCAT_ENABLE(concat_enable)
		    | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE(0) /* Select qualifier slice A(0x0) */
		    | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE(1) /* Select qualifier pin SGPIO9(0x1) */
		    | SGPIO_MUX_CFG_QUALIFIER_MODE(3) /* External SGPIO */
		    | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE(0) /* Select clock source slice D(0x0) */
		    | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE(0) /* Source Clock Pin 0x0 = SGPIO8 */
			| SGPIO_MUX_CFG_EXT_CLK_ENABLE(1) /* External clock signal(pin) selected */
			;

		SGPIO_SLICE_MUX_CFG(slice_index) =
		      SGPIO_SLICE_MUX_CFG_INV_QUALIFIER(0) /* 0x0=Use normal qualifier. */
		    | SGPIO_SLICE_MUX_CFG_PARALLEL_MODE(3) /* 0x3=Shift 1 byte(8bits) per clock. */
		    | SGPIO_SLICE_MUX_CFG_DATA_CAPTURE_MODE(0) /* 0x0=Detect rising edge. (Condition for input bit match interrupt) */
		    | SGPIO_SLICE_MUX_CFG_INV_OUT_CLK(0) /* 0x0=Normal clock. */
		    | SGPIO_SLICE_MUX_CFG_CLKGEN_MODE(1) /* 0x1=Use external clock from a pin or other slice */
		    | SGPIO_SLICE_MUX_CFG_CLK_CAPTURE_MODE(clk_capture_mode) /* 0x0=Use rising clock edge, 0x1=Use falling clock edge */
		    | SGPIO_SLICE_MUX_CFG_MATCH_MODE(0) /* 0x0=Do not match data */
			;

		SGPIO_PRESET(slice_index) = 0;			// External clock, don't care
		SGPIO_COUNT(slice_index) = 0;				// External clock, don't care
		SGPIO_POS(slice_index) =
			  SGPIO_POS_POS_RESET(pos)
			| SGPIO_POS_POS(pos)
			;
		SGPIO_REG(slice_index) = 0x00000000;     // Primary output data register
		SGPIO_REG_SS(slice_index) = 0x00000000;  // Shadow output data register
		
		slice_enable_mask |= (1 << slice_index);
	}

	if( config->slice_mode_multislice == false ) {
		SGPIO_MUX_CFG(slice_gpdma) =
			  SGPIO_MUX_CFG_CONCAT_ORDER(0) /* Self-loop */
			| SGPIO_MUX_CFG_CONCAT_ENABLE(1)
			| SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE(0) /* Select qualifier slice A(0x0) */
			| SGPIO_MUX_CFG_QUALIFIER_PIN_MODE(1) /* Select qualifier pin SGPIO9(0x1) */
			| SGPIO_MUX_CFG_QUALIFIER_MODE(3) /* External SGPIO */
			| SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE(0) /* Select clock source slice D(0x0) */
			| SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE(0) /* Source Clock Pin 0x0 = SGPIO8 */
			| SGPIO_MUX_CFG_EXT_CLK_ENABLE(1) /* External clock signal(pin) selected */
			;

		SGPIO_SLICE_MUX_CFG(slice_gpdma) =
			  SGPIO_SLICE_MUX_CFG_INV_QUALIFIER(0) /* 0x0=Use normal qualifier. */
			| SGPIO_SLICE_MUX_CFG_PARALLEL_MODE(0) /* 0x0=Shift 1 bit per clock. */
			| SGPIO_SLICE_MUX_CFG_DATA_CAPTURE_MODE(0) /* 0x0=Detect rising edge. (Condition for input bit match interrupt) */
			| SGPIO_SLICE_MUX_CFG_INV_OUT_CLK(0) /* 0x0=Normal clock. */
			| SGPIO_SLICE_MUX_CFG_CLKGEN_MODE(1) /* 0x1=Use external clock from a pin or other slice */
			| SGPIO_SLICE_MUX_CFG_CLK_CAPTURE_MODE(clk_capture_mode) /* 0x0=Use rising clock edge, 0x1=Use falling clock edge */
			| SGPIO_SLICE_MUX_CFG_MATCH_MODE(0) /* 0x0=Do not match data */
			;

		SGPIO_PRESET(slice_gpdma) = 0;			// External clock, don't care
		SGPIO_COUNT(slice_gpdma) = 0;			// External clock, don't care
		SGPIO_POS(slice_gpdma) =
			  SGPIO_POS_POS_RESET(0x1f)
			| SGPIO_POS_POS(0x1f)
			;
		SGPIO_REG(slice_gpdma) = 0x11111111;     // Primary output data register, LSB -> out
		SGPIO_REG_SS(slice_gpdma) = 0x11111111;  // Shadow output data register, LSB -> out1
		
		slice_enable_mask |= (1 << slice_gpdma);
	}

	// Start SGPIO operation by enabling slice clocks.
	SGPIO_CTRL_ENABLE = slice_enable_mask;
}
示例#3
0
void test_sgpio_all_slices(void)
{

	SGPIO_GPIO_OENREG = 0; // All inputs for the moment.

	// Disable all counters during configuration
	SGPIO_CTRL_ENABLE = 0;

	// Configure pin functions.
	configure_sgpio_pin_functions();

	/****************************************************/
	/* Enable SGPIO pin outputs. */
	/****************************************************/
	SGPIO_GPIO_OENREG =
        0xFFFF;           // data: output for SGPIO0 to SGPIO15

	for(uint_fast8_t i=0; i<16; i++) 
	{
		SGPIO_OUT_MUX_CFG(i) =
			(0L <<  4) |    // P_OE_CFG = X
			(0L <<  0);     // P_OUT_CFG = 0, dout_doutm1 (1-bit mode)
	}

	/****************************************************/
	/* Slice A to P */
	/****************************************************/
	for(uint_fast8_t i=0; i<16; i++) 
	{
		SGPIO_MUX_CFG(i) = 
			(0L << 12) |    // CONCAT_ORDER = 0 (self-loop)
			(1L << 11) |    // CONCAT_ENABLE = 1 (concatenate data)
			(0L <<  9) |    // QUALIFIER_SLICE_MODE = X
			(0L <<  7) |    // QUALIFIER_PIN_MODE = X
			(0L <<  5) |    // QUALIFIER_MODE = 0 (enable)
			(0L <<  3) |    // CLK_SOURCE_SLICE_MODE = 0, slice D
			(0L <<  1) |    // CLK_SOURCE_PIN_MODE = X
			(0L <<  0);     // EXT_CLK_ENABLE = 0, internal clock signal (slice)

		SGPIO_SLICE_MUX_CFG(i) =
			(0L <<  8) |    // INV_QUALIFIER = 0 (use normal qualifier)
			(0L <<  6) |    // PARALLEL_MODE = 0 (shift 1 bit per clock)
			(0L <<  4) |    // DATA_CAPTURE_MODE = 0 (detect rising edge)
			(0L <<  3) |    // INV_OUT_CLK = 0 (normal clock)
			(0L <<  2) |    // CLKGEN_MODE = 0 (use clock from COUNTER)
			(0L <<  1) |    // CLK_CAPTURE_MODE = 0 (use rising clock edge)
			(0L <<  0);     // MATCH_MODE = 0 (do not match data)

		SGPIO_PRESET(i) = slice_preset_tab[i];
		SGPIO_COUNT(i) = 0;
		SGPIO_POS(i) = (0x1FL << 8) | (0x1FL << 0);
		SGPIO_REG(i) = 0xAAAAAAAA;     // Primary output data register
		SGPIO_REG_SS(i) = 0xAAAAAAAA;  // Shadow output data register
	}

	/****************************************************/
	/* Start SGPIO operation by enabling slice clocks. */
	/****************************************************/
	SGPIO_CTRL_ENABLE = 0xFFFF; /* Start all slices A to P */
/*
		(1L <<  SGPIO_SLICE_D) |    // Slice D
		(1L <<  SGPIO_SLICE_A);     // Slice A
	// Start SGPIO operation by enabling slice clocks.
*/
	/* 
		Expected: 
		MCU Freq MHz = 204
		SGPIO Theorical Freq MHz
		SGPIO00	= 102,00000
		SGPIO01	= 51,00000
		SGPIO02	= 34,00000
		SGPIO03	= 25,50000
		SGPIO04	= 20,40000
		SGPIO05	= 17,00000
		SGPIO06	= 14,57143
		SGPIO07	= 12,75000
		SGPIO08	= 11,33333
		SGPIO09	= 10,20000
		SGPIO10	= 9,27273
		SGPIO11	= 8,50000
		SGPIO12	= 7,84615
		SGPIO13	= 7,28571
		SGPIO14	= 6,80000
		SGPIO15	= 6,37500
		TitanMKD: I have problems with my boards and this test see document Test_SGPIO0_to15.ods / Test_SGPIO0_to15.pdf
	*/
}
示例#4
0
void sgpio_configure(
	const transceiver_mode_t transceiver_mode,
	const bool multi_slice
) {
	// Disable all counters during configuration
	SGPIO_CTRL_ENABLE = 0;

    sgpio_configure_pin_functions();

    // Set SGPIO output values.
	const uint_fast8_t cpld_direction =
		(transceiver_mode == TRANSCEIVER_MODE_TX) ? 1 : 0;
    SGPIO_GPIO_OUTREG =
          (cpld_direction << 11)
        | (1L << 10)	// disable
		;

	// Enable SGPIO pin outputs.
	const uint_fast16_t sgpio_gpio_data_direction =
		(transceiver_mode == TRANSCEIVER_MODE_TX)
		? (0xFF << 0)
		: (0x00 << 0);
	SGPIO_GPIO_OENREG =
		  (1L << 11)	// direction
	    | (1L << 10)	// disable
	    | (0L <<  9)	// capture
	    | (0L <<  8)	// clock
        | sgpio_gpio_data_direction
		;

	SGPIO_OUT_MUX_CFG( 8) =		// SGPIO: Input: clock
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0)
		;
	SGPIO_OUT_MUX_CFG( 9) =		// SGPIO: Input: qualifier
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0)
		;
    SGPIO_OUT_MUX_CFG(10) =		// GPIO: Output: disable
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4)
		;
    SGPIO_OUT_MUX_CFG(11) =		// GPIO: Output: direction
		  SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4)
		;

	const uint_fast8_t output_multiplexing_mode =
		multi_slice ? 11 : 9;
	for(uint_fast8_t i=0; i<8; i++) {
		// SGPIO pin 0 outputs slice A bit "i".
		SGPIO_OUT_MUX_CFG(i) =
		      SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
		    | SGPIO_OUT_MUX_CFG_P_OUT_CFG(output_multiplexing_mode)
			;
	}

	const uint_fast8_t slice_indices[] = {
		SGPIO_SLICE_A,
		SGPIO_SLICE_I,
		SGPIO_SLICE_E,
		SGPIO_SLICE_J,
		SGPIO_SLICE_C,
		SGPIO_SLICE_K,
		SGPIO_SLICE_F,
		SGPIO_SLICE_L,
	};
	
	const uint_fast8_t pos = multi_slice ? 0x1f : 0x03;
	const bool single_slice = !multi_slice;
	const uint_fast8_t slice_count = multi_slice ? 8 : 1;
	
	uint32_t slice_enable_mask = 0;
	for(uint_fast8_t i=0; i<slice_count; i++) {
		const uint_fast8_t slice_index = slice_indices[i];
		const bool input_slice = (i == 0) && (transceiver_mode == TRANSCEIVER_MODE_RX);
		const uint_fast8_t concat_order = (input_slice || single_slice) ? 0 : 3;
		const uint_fast8_t concat_enable = (input_slice || single_slice) ? 0 : 1;
		
		SGPIO_MUX_CFG(slice_index) =
		      SGPIO_MUX_CFG_CONCAT_ORDER(concat_order)
		    | SGPIO_MUX_CFG_CONCAT_ENABLE(concat_enable)
		    | SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE(0)
		    | SGPIO_MUX_CFG_QUALIFIER_PIN_MODE(1)
		    | SGPIO_MUX_CFG_QUALIFIER_MODE(3)
		    | SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE(0)
		    | SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE(0)
			| SGPIO_MUX_CFG_EXT_CLK_ENABLE(1)
			;

		SGPIO_SLICE_MUX_CFG(slice_index) =
		      SGPIO_SLICE_MUX_CFG_INV_QUALIFIER(0)
		    | SGPIO_SLICE_MUX_CFG_PARALLEL_MODE(3)
		    | SGPIO_SLICE_MUX_CFG_DATA_CAPTURE_MODE(0)
		    | SGPIO_SLICE_MUX_CFG_INV_OUT_CLK(0)
		    | SGPIO_SLICE_MUX_CFG_CLKGEN_MODE(1)
		    | SGPIO_SLICE_MUX_CFG_CLK_CAPTURE_MODE(1)
		    | SGPIO_SLICE_MUX_CFG_MATCH_MODE(0)
			;

		SGPIO_PRESET(slice_index) = 0;			// External clock, don't care
		SGPIO_COUNT(slice_index) = 0;				// External clock, don't care
		SGPIO_POS(slice_index) =
			  SGPIO_POS_POS_RESET(pos)
			| SGPIO_POS_POS(pos)
			;
		SGPIO_REG(slice_index) = 0x80808080;     // Primary output data register
		SGPIO_REG_SS(slice_index) = 0x80808080;  // Shadow output data register
		
		slice_enable_mask |= (1 << slice_index);
	}
	
	// Start SGPIO operation by enabling slice clocks.
	SGPIO_CTRL_ENABLE = slice_enable_mask;
}