A (potential) way to share I2C bus with On-board configuration SPI NOR flash of iCE40UL1K-SWG16

Couple month ago I bought some iCE40UL1K-SWG16 from Element14. It’s probably tiniest FPGA Lattice Semi currently offer. The chip package is called Wafer Level CSP. For this chip, 4×4 BGA with 0.35 mm pitch. Crazy small and also low pin count. Despite that size and low pinout. It got Whopping 1248 LUTs and 56kBit of Block ram! It’s tiny potential !

the UL1K has 2 hard IP I2C baked into their silicon. I wanted to use this UL1K as a PWM wave form generator to drive Brushless DC motor with position feedback via some kind of magnetic rotary encoder over i2c bus. The problem is that There’s only 10 I/Os available to user. 3 already used for 3 phase signal for motor, 2 already used for magnetic encoder IC. 1 pin is CDONE. Left last 4 pins that used with SPI NOR chip that store configuration firmware (called bit stream).

Focus on the 4 pins used with SPI NOR. According to the iCE40 Programming and Configuration Technical Note (FPGA-TN-02001-3.3) page 22

Some SPI NOR flash support special command that puts the flash into sleep mode. Normally default iCE40 bit stream configuration doesn’t make use of this feature. But We can enable this function to power down the flash. It means that we can later repurpose those 4 pins to do something else. But hold on a sec, I2C requires Pull up !

It’s possible to reuse SPI_SCK pin and SPI_SO pin of FPGA as I2C. By putting the pull up resistors on those 2 pins. and After the Configuration RAM is loaded from SPI NOR flash. FPGA put the flash to sleep and then reconfigure those 2 pin with SB_IO_OD and later use them with I2C Hard IP

Here’s Example of I2C code that I wrote for iCE40UL1K-SWG16 to drive Brushless motor. Although I didn’t reuse SPI Flash pin. But it can be adapted from this code.

// iCEcube 2 seems to not quite happy with using assign and Hi-z with UL1K
// So SB_IO_OD primitive is required.
//assign io_i2c_sda = sdaoe_i ? 1'bZ : sdaout_i;
//assign sdain_i = io_i2c_sda;

// IO config for I2C Tri-state.
    .PIN_TYPE(6'b 1010_01)   // Simple input + Tri state output opend-drain. 
) sbio_sda (
    .PACKAGEPIN(io_i2c_sda),// Pin name that used in pin constrain file
    .OUTPUTENABLE(sdaoe_i),// Enable is use for switching between Hi-z and Output
// IO config for I2C SCL
    .PIN_TYPE(6'b 0000_01) // Simple input only   
) sbio_scl (
    .PACKAGEPIN(io_i2c_scl),// Pin name that used in pin constrain file

// I2C Primitive of iCE40UL1k
	// Controlling part
	.CLKI(sysclk), // Input clock for IP
	// Register address Part
	// I2C input 
	// I2C output and control
) ; 

At this point. I can’t confirm that this method of sharing pin is working properly. I yet to wait for the PCB of the iCE40UL1K to arrive. So, stay tuned!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s