第27集,软件模拟SPI
SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线。
一般使用4条线:串行时钟线(SCLK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOSI和低电平有效的从机选择线NSS。
模拟SPI读取flash的id
实验箱原理图上标的flash是pm25lv040
但我这个实际上是gd25q40ctig,查看这个flash的spi协议,数据在第一个时钟边沿采样,第二个边沿修改
读取ID的命令,和对应的ID
程序读取结果
代码实现
- typedef enum
- {
- YUYY_SOFT_SPI_MSB = 0,
- YUYY_SOFT_SPI_LSB
- } Yuyy_Soft_Spi_Data_Type;
-
- typedef enum
- {
- YUYY_SOFT_SPI_C1S2 = 0, //第一个边沿修改数据,第2个边沿采样
- YUYY_SOFT_SPI_C2S1
- } Yuyy_Soft_Spi_Data_Sample_Type;
-
- typedef enum
- {
- YUYY_SOFT_SPI_SCK_IDLE_LOW = 0,
- YUYY_SOFT_SPI_SCK_IDLE_HIGH
- } Yuyy_Soft_Spi_Sck_Idle_Type;
-
- #define SOFT_SPI_CS P22
- #define SOFT_SPI_SCK P25
- #define SOFT_SPI_MOSI P23
- #define SOFT_SPI_MISO P24
-
- Yuyy_Soft_Spi_Data_Type spi_dt;
- Yuyy_Soft_Spi_Data_Sample_Type spi_cpha;
- Yuyy_Soft_Spi_Sck_Idle_Type spi_cpol;
-
-
- void yuyy_soft_spi_delay()
- {
- uint8_t i = 3;
- while(i--);
- }
-
- void yuyy_soft_spi_init(Yuyy_Soft_Spi_Data_Type dt,Yuyy_Soft_Spi_Data_Sample_Type cpha,Yuyy_Soft_Spi_Sck_Idle_Type cpol)
- {
- SOFT_SPI_CS = 1;
- spi_dt = dt;
- spi_cpha = cpha;
- spi_cpol = cpol;
- if(spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH)
- SOFT_SPI_SCK = 1;
- else
- SOFT_SPI_SCK = 0;
- SOFT_SPI_MISO = 1;
- SOFT_SPI_MOSI = 1;
- }
-
- void yuyy_soft_spi_cs(uint8_t lev)
- {
- SOFT_SPI_CS = lev;
- yuyy_soft_spi_delay();
- }
-
- void yuyy_soft_spi_write_byte(uint8_t dat)
- {
- uint8_t i = 0;
- while(i<8)
- {
- if(spi_cpha == YUYY_SOFT_SPI_C1S2)
- {
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
- }
- if(spi_dt == YUYY_SOFT_SPI_MSB)
- {
- if(dat & 0x80)
- SOFT_SPI_MOSI = 1;
- else
- SOFT_SPI_MOSI = 0;
- dat <<= 1;
- }
- else
- {
- if(dat & 0x01)
- SOFT_SPI_MOSI = 1;
- else
- SOFT_SPI_MOSI = 0;
- dat >>= 1;
- }
- if(spi_cpha == YUYY_SOFT_SPI_C2S1)
- {
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
- }
- yuyy_soft_spi_delay();
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 1 : 0);
- i++;
- }
- }
-
- uint8_t yuyy_soft_spi_read_byte()
- {
- uint8_t i = 0,dat = 0;
- while(i<8)
- {
- if(spi_cpha == YUYY_SOFT_SPI_C2S1)
- {
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
- }
- if(spi_dt == YUYY_SOFT_SPI_MSB)
- {
- dat <<= 1;
- if(SOFT_SPI_MISO)
- dat |= 0x01;
- else
- dat &= 0xFE;
- }
- else
- {
- dat >>= 1;
- if(SOFT_SPI_MISO)
- dat |= 0x80;
- else
- dat &= 0x7F;
- }
- if(spi_cpha == YUYY_SOFT_SPI_C1S2)
- {
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 0 : 1);
- }
- yuyy_soft_spi_delay();
- SOFT_SPI_SCK = (spi_cpol == YUYY_SOFT_SPI_SCK_IDLE_HIGH ? 1 : 0);
- i++;
- }
- return dat;
- }
-
- void main(void)
- {
- uint8_t id1,id2,id3;
- WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
- EAXFR = 1; //扩展寄存器(XFR)访问使能
- CKCON = 0; //提高访问XRAM速度
-
- RSTFLAG |= 0x04; //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
-
- P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
- P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
- P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
- P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
- P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
- P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
- P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
- P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
-
- //USB调试及复位所需代码-----
- P3M0 &= ~0x03;
- P3M1 |= 0x03;
- IRC48MCR = 0x80;
- while (!(IRC48MCR & 0x01));
- //如果使用USB-CDC需要下面的两行代码
- // USBCLK = 0x00;
- // USBCON = 0x90;
- //如果使用USB-HID注释掉上面两行代码
- usb_init();
- //-------------------------
- yuyy_soft_spi_init(YUYY_SOFT_SPI_MSB,YUYY_SOFT_SPI_C2S1,YUYY_SOFT_SPI_SCK_IDLE_HIGH);
- EUSB = 1; //IE2相关的中断位操作使能后,需要重新设置EUSB
- EA = 1; //打开总中断
- while (P32 != 0);
- yuyy_soft_spi_cs(0);
- yuyy_soft_spi_write_byte(0xAB);
- yuyy_soft_spi_write_byte(0x00);
- yuyy_soft_spi_write_byte(0x00);
- yuyy_soft_spi_write_byte(0x00);
- id1 = yuyy_soft_spi_read_byte();
- yuyy_soft_spi_cs(1);
- printf_hid("发送命令0xAB 读取到ID:0x%02X\r\n",id1);
- delay_ms(100);
-
- yuyy_soft_spi_cs(0);
- yuyy_soft_spi_write_byte(0x90);
- yuyy_soft_spi_write_byte(0x00);
- yuyy_soft_spi_write_byte(0x00);
- yuyy_soft_spi_write_byte(0x00);
- id1 = yuyy_soft_spi_read_byte();
- id2 = yuyy_soft_spi_read_byte();
- yuyy_soft_spi_cs(1);
- printf_hid("发送命令0x90 读取到ID:0x%02X 0x%02X\r\n",id1,id2);
- delay_ms(100);
-
- yuyy_soft_spi_cs(0);
- yuyy_soft_spi_write_byte(0x9F);
- id1 = yuyy_soft_spi_read_byte();
- id2 = yuyy_soft_spi_read_byte();
- id3 = yuyy_soft_spi_read_byte();
- yuyy_soft_spi_cs(1);
- printf_hid("发送命令0x9F 读取到ID:0x%02X 0x%02X 0x%02X\r\n",id1,id2,id3);
- delay_ms(100);
-
- while(1)
- {
- }
- }
复制代码
|