Serial Peripheral Interface 5/23/2013 Richard Kuo Assistant Professor
OutLine Serial Peripheral Interface Introduction 12.NuMicro_SPI.ppt Exercise : use SPI interface to LCD 128x64 (Smpl_SPI_QC12864B) Exercise: use SPI read/write SPI Flash (Smpl_SPI_Flash) Exercise: use SPI & PDMA access SPI Flash (Smpl_SPI2_Flash) Exercise : use SPI interface with RF2.4GHz (Smpl_SPI_RF24L01) Exercise : use SPI interface with RF2.4GHz (Smpl_SPI_A7125)
SPI (Serial Peripheral Interface) Typical SPI connection SPI signals
Daisy-Chain configuration of multiple SPI devices
SPI Write Cycle
SPI Read Cycle
SPI waveform
Daisy Chain Write Cycle
Daisy Chain Read Cycle
SPI Timing Diagram
SPI Timing Parameter
SPI Pin Assignment SPI signals SPI0 SPI1 SPI2 SPI3 CS GPC0 GPC8 GPD0 CLK GPC1 GPC9 GPD1 GPD9 DI0 (MISO) GPC2 GPC10 GPD2 GPD10 DO0 (MOSI) GPC3 GPC11 GPD3 GPD11 DI1 GPC4 GPC12 GPD4 GPD12 DO1 GPC5 GPC13 GPD5 GPD13 Nu-LB-NUC140 On-Board I2S Codec (WAU8822) SD/MMC EEPROM (W25Q16CV) LCD
SPI EEPROM schematic
SPI LCD schematic
SPI Controller Features Up to four SPI controllers Each SPI controller can drive up to two slave devices in master mode Support master/slave mode operation Support 1-channel or 2-channel serial data IN/OUT Configurable data length Provide burst mode operation MSB or LSB first Support Word- and Byte-Suspend function Support DMA-transmitting and DMA-receiving Support SPI mode 0 ~ mode 4
SPI Feature Summary The maximum SPI clock frequency is 20MHz in master mode, 10MHz in slave mode Drive up to eight SPI slave devices in master mode Configurable clock polarity and transfer timing Support two-channel I/O transfer Automatic slave select
SPI block diagram 1-channel I/O 2-channel I/O
One-Channel Master Mode System Diagram 2 Slave Select Prevent from bus conflict
One-Channel Slave Mode System Diagram SPI Clock Slave Select
Two-Channel Master Mode System Diagram
Two-Channel Master Mode Timing Diagram
Smpl_SPI_QC12864B NU-LB-NUC140 + QC12864B NuTiny-SDK-NUC140 + QC12864B QC12864B is a LCD 128x64, its interface is SPI.
Smpl_SPI_QC12864B // LCD QC12864B module // pin 1 : Vss to Gnd // pin 2 : Vcc to Vcc+5V // pin 3 : 0V to N.C. // pin 4 : CS to NUC140 SPI1_CS (GPC8 /pin61) // pin 5 : SID to NUC140 SPI1_DO0 (GPC11/pin58) // pin 6 : SCLK to NUC140 SPI1_CLK (GPC9 /pin60) // pin 7~14: N.C. // pin 15: PSB to Gnd (0=Serial-port mode, 1=Parallel-port mode) // pin 16: N.C. // pin 17: RST to Vcc // pin 18: N.C. // pin 19: LED_A to +5V (Backlight Anode) // pin 20: LED_K to Gnd (Backlight Cathode)
Smpl_SPI_QC12864B void LCD_WriteCommand(uint8_t cmd) { SPI1->SSR.SSR=1; SPI1->TX[0] =0x00F8; SPI1->CNTRL.GO_BUSY = 1; while ( SPI1->CNTRL.GO_BUSY == 1 ); SPI1->TX[0] =0x00F0 & cmd; SPI1->TX[0] =0x00F0 & (cmd<<4); SPI1->SSR.SSR=0; } void LCD_WriteData(unsigned char data) { SPI1->SSR.SSR=1; SPI1->TX[0] =0x00FA; SPI1->CNTRL.GO_BUSY = 1; while ( SPI1->CNTRL.GO_BUSY == 1 ); SPI1->TX[0] =0x00F0 & data; SPI1->TX[0] =0x00F0 & (data<<4); SPI1->SSR.SSR=0; }
Smpl_SPI_QC12864B void Init_QC12864B(void) { LCD_WriteCommand(0x30); DrvSYS_Delay(50); LCD_WriteCommand(0x0c); } void Clear_QC12864B(void) LCD_WriteCommand(0x01); void Print_QC12864B(uint8_t line, unsigned char *string) { uint8_t i, addr; if (line==0) addr = 0x80; else if (line==1) addr = 0x90; else if (line==2) addr = 0x88; else if (line==3) addr = 0x98; else addr = 0x80; LCD_WriteCommand(addr); for (i=0; i<16; i++) LCD_WriteData(*string++); }
Smpl_SPI_QC12864B int main(void) { UNLOCKREG(); DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1); // Enable the 12MHz oscillator oscillation DrvSYS_SelectHCLKSource(0); // HCLK clock source LOCKREG(); DrvSYS_SetClockDivider(E_SYS_HCLK_DIV, 0); // Configure SPI1 as a master to access LCD Q12864B DrvGPIO_InitFunction(E_FUNC_SPI1); DrvSPI_Open(eDRVSPI_PORT1, eDRVSPI_MASTER, eDRVSPI_TYPE1, 8); DrvSPI_SetEndian(eDRVSPI_PORT1, eDRVSPI_MSB_FIRST); DrvSPI_DisableAutoSS(eDRVSPI_PORT1); DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT1, eDRVSPI_ACTIVE_HIGH_RISING);
Smpl_SPI_QC12864B //DrvSPI_EnableInt(eDRVSPI_PORT1, SPI1_Callback, 0); DrvSPI_SetClockFreq(eDRVSPI_PORT1, 50000, 0); // set SPI clock = 50KHz Init_QC12864B(); Clear_QC12864B(); Print_QC12864B(0,"Smpl_SPI_Q12864B"); Print_QC12864B(1,"Academic Example"); Print_QC12864B(2,"Nuvoton NuMicro "); Print_QC12864B(3,"NU-LB-NUC140 "); }
Smpl_GPIO_QC12864B void Init_SPI(void) { DrvGPIO_Open(E_GPC, 8, E_IO_OUTPUT); // SPI_CS DrvGPIO_Open(E_GPC, 9, E_IO_OUTPUT); // SPI_CLK DrvGPIO_Open(E_GPC,11, E_IO_OUTPUT); // SPI_DO DrvGPIO_ClrBit(E_GPC, 8); DrvGPIO_ClrBit(E_GPC, 9); DrvGPIO_ClrBit(E_GPC,11); } void SPI_CS(uint8_t pol) if (pol!=0) DrvGPIO_SetBit(E_GPC, 8); else DrvGPIO_ClrBit(E_GPC, 8);
Smpl_GPIO_QC12864B void SPI_Write(unsigned char zdata) { unsigned int i; for(i=0; i<8; i++) if((zdata << i) & 0x80) DrvGPIO_SetBit(E_GPC, 11); // SID = 1; else DrvGPIO_ClrBit(E_GPC, 11); // SID = 0; DrvGPIO_ClrBit(E_GPC,9); //SCLK = 0; DrvSYS_Delay(10); DrvGPIO_SetBit(E_GPC,9); //SCLK = 1; } Use GPIO pins emulate SPI signals
Smpl_GPIO_QC12864B void LCD_WriteCommand(uint8_t cmd) { SPI_CS(1); SPI_Write(0xF8); SPI_Write(0xF0 & cmd); SPI_Write(0xF0 & (cmd<<4)); SPI_CS(0); } void LCD_WriteData(unsigned char data) { SPI_CS(1); SPI_Write(0xFA); SPI_Write(0xF0 & data); SPI_Write(0xF0 & (data<<4)); SPI_CS(0); }
Smpl_GPIO_QC12864B int main(void) { UNLOCKREG(); DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1); // Enable the 12MHz oscillator oscillation DrvSYS_SelectHCLKSource(0); // HCLK clock source. 0: external 12MHz; 4:internal 22MHz RC oscillator LOCKREG(); Init_SPI(); // Initial GPIOs to emulate SPI pins Init_QC12864B(); // initialize LCD Clear_QC12864B(); // clear LCD Print_QC12864B(0,"Smpl_GPIO_Q12864"); Print_QC12864B(1,"Academic Example"); Print_QC12864B(2,"Nuvoton NuMicro "); Print_QC12864B(3,"NU-LB-NUC140 "); }
SPI Flash Block Diagram
SPI Flash Instruction Table
Smpl_SPI_Flash_PDMA // Configure SPI2 as a master to access SPI-Flash DrvGPIO_InitFunction(E_FUNC_SPI2); // GPIO Init for SPI2 /* Configure SPI2 as a master, Type1 waveform, 32-bit transaction */ DrvSPI_Open(eDRVSPI_PORT2, eDRVSPI_MASTER, eDRVSPI_TYPE1, 32); DrvSPI_SetEndian(eDRVSPI_PORT2, eDRVSPI_MSB_FIRST); // MSB First DrvSPI_DisableAutoSS(eDRVSPI_PORT2); // Disable the automatic slave select function of SS0 /* Set the active level of slave select. */ DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT2, eDRVSPI_ACTIVE_LOW_FALLING); /* Enable the SPI0 interrupt and install the callback function. */ // DrvSPI_EnableInt(eDRVSPI_PORT2, SPI2_Callback, 0); DrvSPI_SetClockFreq(eDRVSPI_PORT2, 1000000, 0); //SPI clock rate 1MHz
SPI Flash Write Enable/Disable
SPI Flash Page Program
Spiflash_PageProgram void SpiFlash_PageProgram(uint32_t StartAddress, uint32_t ByteCount) { uint32_t au32SourceData; DrvSPI_SetBitLength(eDRVSPI_PORT2, 8); // configure transaction length as 8 bits DrvSPI_SetSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: active au32SourceData = 0x06; // send Command: 0x06, Write enable DrvSPI_SingleWrite(eDRVSPI_PORT2, &au32SourceData); while (DrvSPI_IsBusy(eDRVSPI_PORT2)) {} // wait DrvSPI_ClrSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: de-active au32SourceData = 0x02; // send Command: 0x02, Page program DrvSPI_SetBitLength(eDRVSPI_PORT2, 24); // configure transaction length as 24 bits au32SourceData = StartAddress; // send 24-bit start address
Spiflash_PageProgram DrvSPI_SetBitLength(eDRVSPI_PORT2, 8); // configure transaction length as 8 bits DrvSPI_SetPDMA(eDRVSPI_PORT2, eDRVSPI_TX_DMA, TRUE); // enable SPI PDMA // SPI go PDMA1_INT_Flag = 0; DrvSPI_SetGo(eDRVSPI_PORT2); // wait PDMA1 done while (1) { if (PDMA1_INT_Flag) break; } DrvSPI_ClrSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: de-active
SPI Flash Page Erase
SPI Flash Read Mid & Did
SpiFlash_ReadMidDid // For W25Q16BV, Manufacturer ID: 0xEF; Device ID: 0x14 // For W26X16, Manufacturer ID: 0xEF; Device ID: 0x14 void SpiFlash_ReadMidDid(void) { uint32_t au32SourceData; uint32_t au32DestinationData; // configure transaction length as 8 bits DrvSPI_SetBitLength(eDRVSPI_PORT2, 8); DrvSPI_SetSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: active // send Command: 0x90, Read Manufacturer/Device ID au32SourceData = 0x90; DrvSPI_SingleWrite(eDRVSPI_PORT2, &au32SourceData); while (DrvSPI_IsBusy(eDRVSPI_PORT2)) {} // wait // configure transaction length as 24 bits DrvSPI_SetBitLength(eDRVSPI_PORT2, 24); au32SourceData = 0x0; // send 24-bit '0', dummy // configure transaction length as 16 bits DrvSPI_SetBitLength(eDRVSPI_PORT2, 16);
SpiFlash_ReadMidDid // receive au32SourceData = 0x0; DrvSPI_SingleWrite(eDRVSPI_PORT2, &au32SourceData); // wait while (DrvSPI_IsBusy(eDRVSPI_PORT2)) {} // /CS: de-active DrvSPI_ClrSS(eDRVSPI_PORT2, eDRVSPI_SS0); DrvSPI_DumpRxRegister(eDRVSPI_PORT2, &au32DestinationData, 1); if ((au32DestinationData & 0xffff) == 0xEF14) print_lcd(3,"MID & DID=0xEF14"); else print_lcd(3,"MID & DID Error!"); }
SPI Flash Read Status Register
SpiFlash_ReadStatusReg2 uint32_t SpiFlash_ReadStatusReg2(void) { uint32_t au32SourceData; uint32_t au32DestinationData; DrvSPI_SetBitLength(eDRVSPI_PORT2, 16); // configure transaction length as 16 bits DrvSPI_SetSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: active au32SourceData = 0x3500; // send Command: 0x35, Read status register 2 DrvSPI_SingleWrite(eDRVSPI_PORT2, &au32SourceData); while (DrvSPI_IsBusy(eDRVSPI_PORT2)) {} // wait DrvSPI_ClrSS(eDRVSPI_PORT2, eDRVSPI_SS0); // /CS: de-active DrvSPI_DumpRxRegister(eDRVSPI_PORT2, &au32DestinationData, 1); // dump Rx register return (au32DestinationData & 0xFF); }
General Disclaimer The Lecture is strictly used for educational purpose. MAKES NO GUARANTEE OF VALIDITY The lecture cannot guarantee the validity of the information found here. The lecture may recently have been changed, vandalized or altered by someone whose opinion does not correspond with the state of knowledge in the relevant fields. Note that most other encyclopedias and reference works also have similar disclaimers. No formal peer review The lecture is not uniformly peer reviewed; while readers may correct errors or engage in casual peer review, they have no legal duty to do so and thus all information read here is without any implied warranty of fitness for any purpose or use whatsoever. Even articles that have been vetted by informal peer review or featured article processes may later have been edited inappropriately, just before you view them. No contract; limited license Please make sure that you understand that the information provided here is being provided freely, and that no kind of agreement or contract is created between you and the owners or users of this site, the owners of the servers upon which it is housed, the individual Wikipedia contributors, any project administrators, sysops or anyone else who is in any way connected with this project or sister projects subject to your claims against them directly. You are being granted a limited license to copy anything from this site; it does not create or imply any contractual or extracontractual liability on the part of Wikipedia or any of its agents, members, organizers or other users. There is no agreement or understanding between you and the content provider regarding your use or modification of this information beyond the Creative Commons Attribution-Sharealike 3.0 Unported License (CC-BY-SA) and the GNU Free Documentation License (GFDL);
General Disclaimer Personality rights Trademarks Any of the trademarks, service marks, collective marks, design rights or similar rights that are mentioned, used or cited in the lectures are the property of their respective owners. Their use here does not imply that you may use them for any purpose other than for the same or a similar informational use as contemplated by the original authors under the CC-BY-SA and GFDL licensing schemes. Unless otherwise stated , we are neither endorsed by nor affiliated with any of the holders of any such rights and as such we cannot grant any rights to use any otherwise protected materials. Your use of any such or similar incorporeal property is at your own risk. Personality rights The lecture may portray an identifiable person who is alive or deceased recently. The use of images of living or recently deceased individuals is, in some jurisdictions, restricted by laws pertaining to personality rights, independent from their copyright status. Before using these types of content, please ensure that you have the right to use it under the laws which apply in the circumstances of your intended use. You are solely responsible for ensuring that you do not infringe someone else's personality rights.