LPC4350 Sgpio Experimentation
The NXP lpc43xx microcontrollers has an interesting, programmable serial peripheral called the Sgpio (serial GPIO).
It consists of a slew of counters and shift registers that can is configured to serialize and deserialize many channels of Data.
Channels can grouped to create multi-bit parallel data streams.
AN11210 Using Sgpio to emulate an SPI master interface
AN11275 Sgpio on the lpc4300-emulating PWM via Sgpio
AN11343 Sgpio Camera module design using LPC4300
AN11351 implementing a UART using Sgpio on LPC4300
An11196:camera interface Design using Sgpio
Sgpio_i2c_implementation
The current hackrf design entails using the Sgpio peripheral to move quadrature baseband receive and transmit DAT A
Between the USB interface and the baseband ADC/DAC IC.
Because the baseband Adc/dac IC (MAX5864) uses DDR signaling, we expect to use a CPLD to convert bus signaling.
The CPLD may also help manage bus turnaround (between transmit and receive modes)
or interfacing, narrower but faster interfaces to the lpc43xx facilitate.
Because The Jellybean board wasn ' t completed at the time of these experiments,
I used the Diolan lpc-4350-db1-a Development Board.
The despite using a LPC4350 in a BGA256 package, the Sgpio peripheral ' s signals can is mapped to many different pins.
So reworking code to a new set of Sgpio pins should is a trivial matter of switching the SGU configuration for the Affecte D pins.
Sgpio Examples
Some Sgpio Peripheral Examples can be found in the Lpcware repository.
All the source I ' ve found so are focused on generating many i2s interfaces,
Which is not very similar to HACKRF ' s needs.
But reviewing the code was still valuable in grasping how the Sgpio peripheral operates.
There is a few common details to setting up the Sgpio peripheral:
// Configure the PLL to generate a reasonable clock. The SGPIO// will operate with a clock of up to 204MHz (the same as the// M4 clock.CGU_SetPLL1(12);// Set the BASE_PERIPH clock to come from PLL1.CGU_EnableEntity(CGU_BASE_PERIPH, ENABLE);CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_PERIPH);// Compute and commit clock configuration changes.CGU_UpdateClock();
Jiggle sgpio Pins from GPIO Mode
My first test is to ensure I had the right pin (s) hooked up to my scope:
// Jiggle one of the SGPIO pins in GPIO mode, to make sure// I‘m looking at the right pin on the scope.scu_pinmux(9, 0, MD_PLN_FAST, 0);GPIO_SetDir(4, 1L << 12, 1);while(1) { volatile int i; GPIO_SetValue(4, 1L << 12); for(i=0; i<1000; i++); GPIO_ClearValue(4, 1L << 12); for(i=0; i<1000; i++);}
Jiggle Pins from Sgpio Mode
You can also control Sgpio pins, Gpio-style, from within the Sgpio peripheral.
This helped me understand the basics of operating the Sgpio output MUX.
// Set pin to SGPIO mode, toggle output using SGPIO// peripheral registers.scu_pinmux(9, 0, MD_PLN_FAST, 6); // SGPIO0// P_OUT_CFG = 4, gpio_out// P_OE_CFG = XLPC_SGPIO->OUT_MUX_CFG[0] = (0L << 4) | (4L << 0);LPC_SGPIO->GPIO_OENREG |= (1L << 0);while(1) { volatile int i; LPC_SGPIO->GPIO_OUTREG |= (1L << 0); for(i=0; i<1000; i++); LPC_SGPIO->GPIO_OUTREG &= ~(1L << 0); for(i=0; i<1000; i++);}
Serializing Data with Slice Clock Source
My First full-on Sgpio experiment involved serializing a data pattern from slice A,
Using slice D to generate a SGPIO_CLK/2 data rate.
I derived the code from examples that configured the Sgpio as I2S interfaces:
//Disable All counters during configurationlpc_sgpio->ctrl_enabled =0;//Configure pin functions.Scu_pinmux (9,0, Md_pln_fast,6);//SGPIO0Scu_pinmux (2,3, Md_pln_fast,0);//SGPIO12//Enable sgpio pin outputs.Lpc_sgpio->gpio_oenreg = (1L<< A) |//SGPIO12(1L<<0);//SGPIO0//sgpio pin 0 outputs slice A bit 0.lpc_sgpio->out_mux_cfg[0] = (0L<<4) |//p_oe_cfg = X(0L<<0);//p_out_cfg = 0, DOUT_DOUTM1 (1-bit mode)//sgpio pin outputs slice D bit 0.lpc_sgpio->out_mux_cfg[ A] = (0L<<4) |//p_oe_cfg = X(0L<<0);//p_out_cfg = 0, DOUT_DOUTM1 (1-bit mode)//Slice Alpc_sgpio->sgpio_mux_cfg[0] = (0L<< A) |//concat_order = 0 (self-loop)(1L<< One) |//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)Lpc_sgpio->slice_mux_cfg[0] = (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 (does not MATCH data)Lpc_sgpio->preset[0] =1; Lpc_sgpio->count[0] =0; Lpc_sgpio->pos[0] = (0X1FL<<8) | (0X1FL<<0); Lpc_sgpio->reg[0] =0xAAAAAAAA;//Primary output Data Registerlpc_sgpio->reg_ss[0] =0xAAAAAAAA;//Shadow output Data Register//Slice D (clock for Slice A)lpc_sgpio->sgpio_mux_cfg[3] = (0L<< A) |//concat_order = 0 (self-loop)(1L<< One) |//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)Lpc_sgpio->slice_mux_cfg[3] = (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 (does not MATCH data)Lpc_sgpio->preset[3] =0; Lpc_sgpio->count[3] =0; Lpc_sgpio->pos[3] = (0X1FL<<8) | (0X1FL<<0); Lpc_sgpio->reg[0] =0xAAAAAAAA;//Primary output Data Registerlpc_sgpio->reg_ss[0] =0xAAAAAAAA;//Shadow output Data Register//Start Sgpio operation by enabling slice clocks.lpc_sgpio->ctrl_enabled = (1L<<3) |//Slice D(1L<<0);//Slice A
LPC4350 Sgpio Experimentation