- void spi_init()
- {
- SPI_InitTypeDef SPI_InitStructure = {0};
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- __RCC_GPIOA_CLK_ENABLE();
- __RCC_SPI1_CLK_ENABLE();
-
- PA10_AFx_SPI1SCK();
- PA11_AFx_SPI1MISO();
- PA12_AFx_SPI1MOSI();
- PA15_AFx_SPI1CS();
-
- GPIO_InitStructure.Pins = GPIO_PIN_10|GPIO_PIN_12|GPIO_PIN_15;
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
-
- GPIO_InitStructure.Pins = GPIO_PIN_11;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
-
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 双线全双工
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主机模式
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 帧数据长度为8bit
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // 时钟空闲电平为高
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 第二个边沿采样
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 片选信号由SSI寄存器控制
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 波特率为PCLK的8分频
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 最高有效位 MSB 收发在前
- SPI_InitStructure.SPI_Speed = SPI_Speed_High; // 高速SPI
- SPI_Init(CW_SPI1, &SPI_InitStructure);
- SPI_Cmd(CW_SPI1, ENABLE);
-
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- }
读Flash id,需要注意的是在全双工模式下读之前要先发送,不然无法接受从设备发过来的数据
- uint8_t spi_sendbyte(SPI_TypeDef* SPIx,uint8_t data)
- {
- while(SPI_GetFlagStatus(SPIx, SPI_FLAG_TXE) == RESET);
- SPI_SendData(SPIx,data);
- while(SPI_GetFlagStatus(SPIx, SPI_FLAG_RXNE) == RESET);
- return SPI_ReceiveData(SPIx)&0xFF;
- }
- uint8_t spi_readbyte(SPI_TypeDef* SPIx)
- {
- return spi_sendbyte(SPIx,0x00);
- }
- void cw25q64_readflashid()
- {
- uint8_t data[8] = {0},i=0;
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x90);
- spi_sendbyte(CW_SPI1,0x00);
- spi_sendbyte(CW_SPI1,0x00);
- spi_sendbyte(CW_SPI1,0x00);
- data[0] = spi_readbyte(CW_SPI1);
- data[1] = spi_readbyte(CW_SPI1);
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash read Manufacturer/Device ID %02X %02X\n",data[0],data[1]);
-
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x9F);
- data[0] = spi_readbyte(CW_SPI1);
- data[1] = spi_readbyte(CW_SPI1);
- data[2] = spi_readbyte(CW_SPI1);
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash read JEDEC ID %02X %02X%02X\n",data[0],data[1],data[2]);
-
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x5A);
- spi_sendbyte(CW_SPI1,0x00);
- spi_sendbyte(CW_SPI1,0x00);
- spi_sendbyte(CW_SPI1,0xF8);
- spi_sendbyte(CW_SPI1,0x00);
- while(i<8)
- {
- data[i] = spi_readbyte(CW_SPI1);
- i++;
- }
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash read Unique Id %02X%02X%02X%02X%02X%02X%02X%02X\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
- }
运行结果
Device ID的ID7 - ID0这个值实际读到的和手册不一致
Unique Id是01开头F6结尾
接下来尝试写入数据,先要使能写入,然后擦除,等待擦除完成后写入数据
- void cw25q64_waitwritefinish()
- {
- uint8_t writebusy = 1;
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x05);
- while(writebusy != 0)
- {
- writebusy = spi_readbyte(CW_SPI1)&0x01;
- }
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash write finish\n");
- }
- void cw25q64_writeenable()
- {
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x06);
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash write enabled\n");
- }
- void cw25q64_erasesector(uint32_t secteraddr)
- {
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x20);
- spi_sendbyte(CW_SPI1,(secteraddr >> 16)&0xFF);
- spi_sendbyte(CW_SPI1,(secteraddr >> 8)&0xFF);
- spi_sendbyte(CW_SPI1,secteraddr&0xFF);
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash erase sector %08X\n",secteraddr);
- }
- void cw25q64_writepagedata(uint32_t pageaddr,uint8_t *datas,uint16_t len)
- {
- uint16_t index = 0;
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x02);
- spi_sendbyte(CW_SPI1,(pageaddr >> 16)&0xFF);
- spi_sendbyte(CW_SPI1,(pageaddr >> 8)&0xFF);
- spi_sendbyte(CW_SPI1,pageaddr&0xFF);
- while(index < len)
- {
- spi_sendbyte(CW_SPI1,datas[index]);
- index += 1;
- }
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash write page %08X data:\n",pageaddr);
- index = 0;
- while(index < len)
- {
- printf("%02X ",datas[index]);
- index += 1;
- }
- printf("\n");
- }
- void cw25q64_readdata(uint32_t addr,uint8_t *datas,uint16_t len)
- {
- uint16_t index = 0;
- SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
- spi_sendbyte(CW_SPI1,0x03);
- spi_sendbyte(CW_SPI1,(addr >> 16)&0xFF);
- spi_sendbyte(CW_SPI1,(addr >> 8)&0xFF);
- spi_sendbyte(CW_SPI1,addr&0xFF);
- while(index < len)
- {
- datas[index] = spi_readbyte(CW_SPI1)&0xFF;
- index += 1;
- }
- SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
- printf("Flash read %08X data:\n",addr);
- index = 0;
- while(index < len)
- {
- printf("%02X ",datas[index]);
- index += 1;
- }
- printf("\n");
- }
- int32_t main(void)
- {
- uint8_t flash_testdata[50] = {0},index = 0;
- RCC_HSI_48M_init();
- RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
- RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
- uart1_init();
- spi_init();
- cw25q64_readflashid();
- while(index < 50)
- {
- index += 1;
- flash_testdata[index] = index;
- }
- cw25q64_writeenable();
- cw25q64_erasesector(0);
- cw25q64_waitwritefinish();
- cw25q64_writeenable();
- cw25q64_writepagedata(0,flash_testdata,50);
- cw25q64_waitwritefinish();
- cw25q64_readdata(0,flash_testdata,50);
- while (1)
- {
- }
- }
运行结果
除了读写FLASH,这块LCD12864的屏幕也可以用SPI驱动
驱动它要用到5个IO,CS RST A0 MOSI SCK,SPI只用发送模式就可以了MISO可以不用,这里换一组IO
- YUYY_HS12864G18B_DEV_t hs12864_dev;
- void hs12864g18b_init(void)
- {
- GPIO_InitTypeDef gpiodef;
- hs12864_dev.cs.gpio = CW_GPIOA;
- hs12864_dev.cs.pin = GPIO_PIN_4;
- hs12864_dev.rst.gpio = CW_GPIOA;
- hs12864_dev.rst.pin = GPIO_PIN_3;
- hs12864_dev.a0.gpio = CW_GPIOA;
- hs12864_dev.a0.pin = GPIO_PIN_2;
- hs12864_dev.sck.gpio = CW_GPIOA;
- hs12864_dev.sck.pin = GPIO_PIN_5;
- hs12864_dev.mo.gpio = CW_GPIOA;
- hs12864_dev.mo.pin = GPIO_PIN_7;
-
- __RCC_GPIOA_CLK_ENABLE();
- gpiodef.Pins = GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_4|GPIO_PIN_3|GPIO_PIN_2;
- gpiodef.Mode = GPIO_MODE_OUTPUT_PP;
- gpiodef.IT = GPIO_IT_NONE;
- GPIO_Init(CW_GPIOA,&gpiodef);
-
- #if(YUYY_HS12864G18B_USE_SOFT_SPI)
- yuyy_hs12864g18b_set_spigpio(NULL,&hs12864g18b_gpio_config);
- #else
- __RCC_SPI1_CLK_ENABLE();;
- PA05_AFx_SPI1SCK();
- PA07_AFx_SPI1MOSI();
- SPI_InitTypeDef spidef;
- spidef.SPI_Direction = SPI_Direction_1Line_TxOnly;
- spidef.SPI_Mode = SPI_Mode_Master;
- spidef.SPI_DataSize = SPI_DataSize_8b;
- spidef.SPI_CPOL = SPI_CPOL_High;
- spidef.SPI_CPHA = SPI_CPHA_2Edge;
- spidef.SPI_NSS = SPI_NSS_Soft;
- spidef.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
- spidef.SPI_FirstBit = SPI_FirstBit_MSB;
- spidef.SPI_Speed = SPI_Speed_High;
- SPI_Init(CW_SPI1,&spidef);
- SPI_Cmd(CW_SPI1, ENABLE);
- hs12864_dev.spix = CW_SPI1;
- #endif
- yuyy_hs12864g18b_init(&hs12864_dev);
- }
- int32_t main(void)
- {
- RCC_HSI_48M_init();
- RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
- RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
- hs12864g18b_init();
- yuyy_hs12864g18b_clear_screen(&hs12864_dev);
- yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,0,0,(uint8_t *)"CW32L031TEST");
- yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,2,0,(uint8_t *)"Drivered by SPI");
- yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,0,(uint8_t *)"Code by yuyy1989");
- while (1)
- {
- }
- }
运行效果
另外SPI还能用来驱动WS2812或SK6812这样的幻彩灯珠,这里就先不演示了