前言
最近项目上遇到困难,esp8266的SPI用起来有点晕,硬件SPI驱动代码研究不透,猜想应该像STM32操作寄存器一样,可是现在水平有限还是没啃下来,只做到esp8266 硬件SPI发送命令字(一个字节)到stm32,stm32正确的接收到了数据,但关键的问题还是想把esp8266 硬件SPI驱动搞懂,esp8266中HSPI发送数据格式为:命令字 + 地址 + 数据,分别对应不同的底层代码。现在先把硬件SPI驱动代码记录下来,待后续3.0版本的sdk 更新外设SPI驱动后对比学习下,自己也实现了IO口模拟SPI通信,使用逻辑分析仪测试觉得速度还可以接受,也附在这篇博客中。
一. 硬件HSPI
来自esp github,驱动代码也在HSPI_Master/driver路径下。
用例:
#include "gpio.h"
#include "spi_register.h"
#include "spi_interface.h"
void spi_initialize()
{
//Initialze Pins on ESP8266
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_HSPIQ_MISO);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_HSPI_CS0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_HSPID_MOSI);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_HSPI_CLK);
SpiAttr pAttr; //Set as Master/Sub mode 0 and speed 10MHz
pAttr.mode = SpiMode_Master;
pAttr.subMode = SpiSubMode_0;
pAttr.speed = SpiSpeed_10MHz;
pAttr.bitOrder = SpiBitOrder_MSBFirst;
SPIInit(SpiNum_HSPI, &pAttr);
}
void Send_cmd(uint8 command)
{
SpiData pDat;
pDat.cmd = command; ///< Command value
pDat.cmdLen = 1; ///< Command byte length
pDat.addr = NULL; ///< Point to address value
pDat.addrLen = 0; ///< Address byte length
pDat.data = NULL; ///< Point to data buffer
pDat.dataLen = 0; ///< Data byte length.
SPIMasterSendData(SpiNum_HSPI, &pDat);
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
void user_init(void)
{
uint8 cmd = 0xaa;
uint32 addr = 0xbbcc;
uint32 data[2] = { 0x11223344, 0x55667788 };
spi_initialize();
printf("Starting SPI Communication\n");
while (1) {
Send_cmd(0x34);
SpiData pDat;
pDat.cmd = cmd; ///< Command value
pDat.cmdLen = 1; ///< Command byte length
pDat.addr = &addr; ///< Point to address value
pDat.addrLen = 2; ///< Address byte length
pDat.data = data; ///< Point to data buffer
pDat.dataLen = sizeof(data); ///< Data byte length.
SPIMasterSendData(SpiNum_HSPI, &pDat);
vTaskDelay(100);
}
}
二. 软件SPI
软件SPI可能速度较慢,我自己测试了IO口速度大概是1.75翻转一次,也就是570k,比串口速度好多了。
用例:
LOCAL void spi_task(void *pvParameters)
{
SOFT_SPI_INIT();
while(1){
softspi_write_byte(0x08);
softspi_write_byte(0x03);
softspi_write_byte(0x04);
softspi_write_byte(0x0A);
vTaskDelay(5);
//printf("spi test\n");
}
vTaskDelete(NULL);
}
驱动代码 :
/*
* soft spi.c
*
* Created on: 2018年8月10日
* Author: Hynson
*/
#include "soft_spi.h"
/* spi write one byte */
void ICACHE_FLASH_ATTR softspi_write_byte(u8 data)
{
u8 i;
CS_0();
for(i = 0; i < 8; i++){
if (data & 0x80){
MOSI_1();
}else{
MOSI_0();
}
SCK_0();
data <<= 1;
SCK_1();
}
CS_1();
}
/* spi read one byte */
u8 ICACHE_FLASH_ATTR softspi_read_byte(void)
{
u8 read = 0;
u8 i;
CS_0();
for (i = 0; i < 8; i++){
SCK_0();
read = read<<1;
if (MISO_IS_HIGH()){
read++;
}
SCK_1();
}
CS_1();
return read;
}
/*
* soft_spi.h
*
* Created on: 2018年11月24日
* Author: Hynson
*/
#ifndef __SOFT_SPI_H_
#define __SOFT_SPI_H_
#include "c_types.h"
#include "gpio.h"
#include "esp8266/gpio_register.h"
#include "esp8266/eagle_soc.h"
#include "esp8266/pin_mux_register.h"
#include "esp8266/ets_sys.h"
#define SPI_MISO 12
#define SPI_MOSI 13
#define SPI_SCK 14
#define SPI_CS 15
#define SOFT_SPI_INIT() do{\
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);\
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);\
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14);\
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15);\
GPIO_DIS_OUTPUT(SPI_MISO);\
}while(0)
#define MOSI_0() GPIO_OUTPUT_SET(SPI_MOSI, 0)
#define MOSI_1() GPIO_OUTPUT_SET(SPI_MOSI, 1)
#define CS_0() GPIO_OUTPUT_SET(SPI_CS, 0)
#define CS_1() GPIO_OUTPUT_SET(SPI_CS, 1)
#define SCK_0() GPIO_OUTPUT_SET(SPI_SCK, 0)
#define SCK_1() GPIO_OUTPUT_SET(SPI_SCK, 1)
#define MISO_IS_HIGH() (GPIO_INPUT_GET(SPI_MISO) != 0)
u8 ICACHE_FLASH_ATTR softspi_read_byte(void);
void ICACHE_FLASH_ATTR softspi_write_byte(u8 data);
#endif /* __SOFT_SPI_H_ */
esp8266和STM32 51单片机 spi通信网上也找了好久 查找了好多资料,关于这方面的还真是比较少,觉得比较好的文章见下面参考。
参考: