IO口模拟SPI
根据SPI通信规范,与IO口模拟I2C类似,通过普通IO端口模拟也可以实现单片机(主设备)与从设备的SPI通信,其中使能信号CS在开始SPI通信前置低,在通信结束后置高,时钟线SCK通过IO口延时高低电平变化实现,MOSI,MISO根据SCK状态实现发送接收数据等,以下是相关代码
/*
* spi_m_flash.c
*
* Created on: 2019年7月13日
* Author: liangfeng
*/
#include "aworks.h" /* 此头文件必须被首先包含 */
#include "aw_spi.h"
#include "aw_gpio.h"
#include "aw_delay.h"
#include "imx1050_pin.h"
#include "spi_m_flash.h"
#include "pattern.h"
#include "driver/enc/awbl_enc_service.h"
#include "driver/enc/awbl_enc.h"
#define SPI_CS_PIN 20 //GPIO1_27
#define SPI_MOSI_PIN 9 //GPIO1_29
#define SPI_MISO_PIN 10 //GPIO1_30
#define SPI_SCK_PIN 11 //GPIO1_31
/** \操作代码 */
#define WREN 0x06 /* 写使能 */
#define WRDI 0x04 /* 复位写使能锁存器 */
#define RDSR 0x05 /* 读取状态寄存器 */
#define WRSR 0x01 /* 写入状态寄存器*/
#define READ 0x03 /* 读内存代码命令 */
#define WRITE 0x02 /* 写内存代码命令 */
#define RDID 0x9F /* 读器件 ID */
#define SPI_SCK_L aw_gpio_set(GPIO1_11,0)
#define SPI_SCK_H aw_gpio_set(GPIO1_11,1)
#define SPI_MOSI_L aw_gpio_set(GPIO1_9,0)
#define SPI_MOSI_H aw_gpio_set(GPIO1_9,1)
#define SPI_CS_L aw_gpio_set(GPIO1_20,0)
#define SPI_CS_H aw_gpio_set(GPIO1_20,1)
//io口初始化
void IO_FM_GPIO_Init(void)
{
static const int spi_pins_tabe[] = {
GPIO1_20,
GPIO1_9,
GPIO1_10,
GPIO1_11,
};
if(aw_gpio_pin_request("spi_pins", &spi_pins_tabe, 4)== AW_OK){
aw_gpio_pin_cfg(GPIO1_20, AW_GPIO_OUTPUT | AW_GPIO_PULL_UP );//CS片选
aw_gpio_pin_cfg(GPIO1_9, AW_GPIO_OUTPUT | AW_GPIO_PULL_UP );//MOSI
aw_gpio_pin_cfg(GPIO1_10, AW_GPIO_INPUT | AW_GPIO_PULL_UP );//MISO
aw_gpio_pin_cfg(GPIO1_11, AW_GPIO_OUTPUT | AW_GPIO_PULL_UP );//SCK
}
}
//发送一个字节数据
void IO_FM_SendOneByte(uint8_t data)
{
uint8_t i;
//aw_udelay(1);
SPI_SCK_L;
for(i=0;i<8;i++)
{
SPI_SCK_L;
//aw_udelay(1);
if(data&(0x80>>i))
{
SPI_MOSI_H;
}
else
{
SPI_MOSI_L;
}
//aw_udelay(1);
SPI_SCK_H;
//aw_udelay(1);
}
//aw_udelay(1);
}
//接收一个字节数据
uint8_t IO_FM_ReceiveOneByte(void)
{
uint8_t temp=0x00;
SPI_SCK_H;
for(int i=0;i<8;i++){
SPI_SCK_H;
//aw_udelay(1);
SPI_SCK_L;
//aw_udelay(1);
if(aw_gpio_get(GPIO1_10)){
temp |= 1<<(7-i);
}
//aw_udelay(1);
}
SPI_SCK_L;
return temp;
}
//发送数据
void IO_FM_SendBytes(uint16_t length,uint8_t *sbuff)
{
for(int i=0;i<length;i++){
IO_FM_SendOneByte(sbuff[i]);
}
}
//接收数据
void IO_FM_ReceiveBytes(uint16_t length,uint8_t *rbuff)
{
for(int i=0;i<length;i++){
rbuff[i] = IO_FM_ReceiveOneByte();
}
}
//读状态寄存器
uint8_t __is_flash_busy (void)
{
uint8_t reg;
/* 发送 RDSR 命令 */
IO_FM_SendOneByte(RDSR);
//aw_udelay(1);
reg = IO_FM_ReceiveOneByte();
return reg;
}
//发送数据
void IO_FM_WriteData(uint32_t Addr,uint16_t Length,uint8_t *sbuff)
{
uint8_t addr_L1;
//uint8_t addr_H1;
uint8_t addr_L2;
addr_L1 = (uint8_t)(Addr&0xff);
addr_L2 = (uint8_t)((Addr>>8)&0xff);
//addr_H1 = (uint8_t)(Addr>>16)&0xff;
//addr_H2 = (uint8_t)((Addr>>24)&0xff);
SPI_CS_L;
//aw_udelay(1);
IO_FM_SendOneByte(WREN); //发送写使能
SPI_CS_H;
//aw_udelay(1);
SPI_CS_L;
//aw_udelay(1);
IO_FM_SendOneByte(WRITE);//写
//IO_Flash_SendOneByte(addr_H2);
//IO_FM_SendOneByte(addr_H1);
IO_FM_SendOneByte(addr_L2);
IO_FM_SendOneByte(addr_L1);
IO_FM_SendBytes(Length,sbuff);
SPI_CS_H;
//aw_udelay(1);
}
//读取数据
void IO_FM_ReadData(uint32_t Addr,uint16_t length,uint8_t *rbuff)
{
uint8_t addr_L1;
//uint8_t addr_H1;
uint8_t addr_L2;
addr_L1 = (uint8_t)(Addr&0xff);
addr_L2 = (uint8_t)((Addr>>8)&0xff);
//addr_H1 = (uint8_t)(Addr>>16)&0xff;
// addr_H2 = (uint8_t)((Addr>>24)&0xff);
SPI_CS_L;
//aw_udelay(1);
IO_FM_SendOneByte(WREN); //发送写使能
SPI_CS_H;
//aw_udelay(1);
SPI_CS_L;
//aw_udelay(1);
IO_FM_SendOneByte(READ);//读
// IO_Flash_SendOneByte(addr_H2);
// IO_FM_SendOneByte(addr_H1);
IO_FM_SendOneByte(addr_L2);
IO_FM_SendOneByte(addr_L1);
IO_FM_ReceiveBytes(length,rbuff);
SPI_CS_H;
//aw_udelay(1);
}
上面是io口模拟spi读取,写入铁电数据。