关于esp8266使用hspi做从机(slave)遇到的问题
关于esp8266使用hspi做从机(slave)遇到的问题
Postby ldcung » Tue Jul 12, 2016 11:47 pm
大家好,我在官方提供的ESP8266_NONOS_SDK V1.5.4中的AT工程基础上进行开发,我尝试使用esp8266的HSPI做为从机(Hspi slave)接收外部mcu发来的数据,但是在实现的过程中遇到一些问题。
我根据8J-ESP8266__SPI-WiFi_Passthrough_2-Interrupt_Mode__CN_v0.1.pdf文档中spi从机通信协议的说明,把外部mcu(spi 主机)设置成spi mode0,通信速率设置为500K,每次发送34个字节(命令0x02+地址0x00+32字节数据)。设置完成后,我通过逻辑分析仪捕获spi主机输出的波形,是我期望输出的波形。
然后,我在ESP8266程序里做了如下工作:
1.有用户程序初始化函数里初始化了spi从机。代码如下:
void ICACHE_FLASH_ATTR user_init(void)
{
led_gpio_init();
user_link_led_timer_init();
at_init();
at_port_print("\r\nready\r\n");
spi_slave_init(HSPI, 32);
}
spi_slave_init函数内容是采用官方默认的,并没有做修改。
2.在spi的从机中断函数void spi_slave_isr_handler(void *para)中添加了一些打印语句,代码如下:
void spi_slave_isr_handler(void *para)
{
uint32 regvalue,calvalue;
static uint8 state =0;
uint32 recv_data,send_data;
os_printf("spi_slave_isr\n");
if(READ_PERI_REG(0x3ff00020)&BIT4)
{
//following 3 lines is to clear isr signal
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
}
else if(READ_PERI_REG(0x3ff00020)&BIT7)
{ //bit7 is for hspi isr,
os_printf("hspi ISR\n");
regvalue=READ_PERI_REG(SPI_SLAVE(HSPI));
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),//关闭中断使能
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),//清中断标志
SPI_TRANS_DONE|
SPI_SLV_WR_STA_DONE|
SPI_SLV_RD_STA_DONE|
SPI_SLV_WR_BUF_DONE|
SPI_SLV_RD_BUF_DONE);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI), //中断使能
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
if(regvalue&SPI_TRANS_DONE)//传输完成?
{
os_printf("translate done\n");
}
if(regvalue&SPI_SLV_WR_BUF_DONE)//写从机buff完成?
{
os_printf("write buff done\n");
GPIO_OUTPUT_SET(0, 0);
//将寄存器接收数据搬入内存
idx=0;
while(idx<8)//取8次,每次取出一个32位数,共取出32*8=256位,也即32个字节
{
recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
spi_data[idx<<2] = recv_data&0xff;
spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
idx++;
}
//add system_os_post here
GPIO_OUTPUT_SET(0, 1);//用于通知主机,数据已经读取完成
os_printf("receive finish\n");
}
if(regvalue&SPI_SLV_RD_BUF_DONE)
{
os_printf("read buff done\n");
//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.
GPIO_OUTPUT_SET(2, 0);
//add system_os_post here
//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);
}
}
else if(READ_PERI_REG(0x3ff00020)&BIT9)
{ //bit7 is for i2s isr,
os_printf("3\n");
}
}
在进行主机从机通信测试时,用主机一次发送34字节(命令0x02+地址0x00+32字节数据),结果发现os_printf("hspi ISR\n");被执行了十几次(约12次,每次打印出的字符串条数有差异),也即 else if(READ_PERI_REG(0x3ff00020)&BIT7)判断条件被触发约12次,而每次对应 if(regvalue&SPI_TRANS_DONE)条件也均会满足,os_printf("translate done\n");会执行并打印字符串。但是 if(regvalue&SPI_SLV_WR_BUF_DONE)条件总是不满足。当我尝试用主机发送读数据指令(0x03,0x00)时,得到的效果也如上所述,并不会触发if(regvalue&SPI_SLV_RD_BUF_DONE)。我尝试打印出regvalue的值,得到的结果为0x66f003f0,每次得到的结果不同,但是最后的三个数字总是3f0。
我现在的疑问是
1.主机一次发送34字节时,为什么会触发进入中断函数十几次,而不是一次,不是34次?
2.为什么SPI_SLV_WR_BUF_DONE和SPI_SLV_RD_BUF_DONE条件总是不被触发?是不是我哪里没有配置好,或者测试的方法有误?
另外,我尝试过用HSPI做为master主动往外发出数据,用逻辑分析仪观察波形,可以得到相应的波形,可以确定hspi的引脚是没有弄错的。
如果哪位朋友有做过,还请不吝指点,不胜感激!!!
我根据8J-ESP8266__SPI-WiFi_Passthrough_2-Interrupt_Mode__CN_v0.1.pdf文档中spi从机通信协议的说明,把外部mcu(spi 主机)设置成spi mode0,通信速率设置为500K,每次发送34个字节(命令0x02+地址0x00+32字节数据)。设置完成后,我通过逻辑分析仪捕获spi主机输出的波形,是我期望输出的波形。
然后,我在ESP8266程序里做了如下工作:
1.有用户程序初始化函数里初始化了spi从机。代码如下:
void ICACHE_FLASH_ATTR user_init(void)
{
led_gpio_init();
user_link_led_timer_init();
at_init();
at_port_print("\r\nready\r\n");
spi_slave_init(HSPI, 32);
}
spi_slave_init函数内容是采用官方默认的,并没有做修改。
2.在spi的从机中断函数void spi_slave_isr_handler(void *para)中添加了一些打印语句,代码如下:
void spi_slave_isr_handler(void *para)
{
uint32 regvalue,calvalue;
static uint8 state =0;
uint32 recv_data,send_data;
os_printf("spi_slave_isr\n");
if(READ_PERI_REG(0x3ff00020)&BIT4)
{
//following 3 lines is to clear isr signal
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
}
else if(READ_PERI_REG(0x3ff00020)&BIT7)
{ //bit7 is for hspi isr,
os_printf("hspi ISR\n");
regvalue=READ_PERI_REG(SPI_SLAVE(HSPI));
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),//关闭中断使能
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);
CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),//清中断标志
SPI_TRANS_DONE|
SPI_SLV_WR_STA_DONE|
SPI_SLV_RD_STA_DONE|
SPI_SLV_WR_BUF_DONE|
SPI_SLV_RD_BUF_DONE);
SET_PERI_REG_MASK(SPI_SLAVE(HSPI), //中断使能
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
if(regvalue&SPI_TRANS_DONE)//传输完成?
{
os_printf("translate done\n");
}
if(regvalue&SPI_SLV_WR_BUF_DONE)//写从机buff完成?
{
os_printf("write buff done\n");
GPIO_OUTPUT_SET(0, 0);
//将寄存器接收数据搬入内存
idx=0;
while(idx<8)//取8次,每次取出一个32位数,共取出32*8=256位,也即32个字节
{
recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
spi_data[idx<<2] = recv_data&0xff;
spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
idx++;
}
//add system_os_post here
GPIO_OUTPUT_SET(0, 1);//用于通知主机,数据已经读取完成
os_printf("receive finish\n");
}
if(regvalue&SPI_SLV_RD_BUF_DONE)
{
os_printf("read buff done\n");
//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.
GPIO_OUTPUT_SET(2, 0);
//add system_os_post here
//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);
}
}
else if(READ_PERI_REG(0x3ff00020)&BIT9)
{ //bit7 is for i2s isr,
os_printf("3\n");
}
}
在进行主机从机通信测试时,用主机一次发送34字节(命令0x02+地址0x00+32字节数据),结果发现os_printf("hspi ISR\n");被执行了十几次(约12次,每次打印出的字符串条数有差异),也即 else if(READ_PERI_REG(0x3ff00020)&BIT7)判断条件被触发约12次,而每次对应 if(regvalue&SPI_TRANS_DONE)条件也均会满足,os_printf("translate done\n");会执行并打印字符串。但是 if(regvalue&SPI_SLV_WR_BUF_DONE)条件总是不满足。当我尝试用主机发送读数据指令(0x03,0x00)时,得到的效果也如上所述,并不会触发if(regvalue&SPI_SLV_RD_BUF_DONE)。我尝试打印出regvalue的值,得到的结果为0x66f003f0,每次得到的结果不同,但是最后的三个数字总是3f0。
我现在的疑问是
1.主机一次发送34字节时,为什么会触发进入中断函数十几次,而不是一次,不是34次?
2.为什么SPI_SLV_WR_BUF_DONE和SPI_SLV_RD_BUF_DONE条件总是不被触发?是不是我哪里没有配置好,或者测试的方法有误?
另外,我尝试过用HSPI做为master主动往外发出数据,用逻辑分析仪观察波形,可以得到相应的波形,可以确定hspi的引脚是没有弄错的。
如果哪位朋友有做过,还请不吝指点,不胜感激!!!
Re: 关于esp8266使用hspi做从机(slave)遇到的问题
Postby ldcung » Wed Jul 13, 2016 3:02 pm
我发现了问题所在。由于对spi通信不熟悉,导致接线错误,才导致了上面的现象。spi主机和从机之间接线应该是这样的:
CS--------CS
MOSI--------MOSI
MISO--------MISO
CLK--------CLK
但是我把MOSI和MISO交叉接了,即主机MOSI接了从机的MISO,而主机的MISO接了从机的MOSI,这是不对的。
我更换回来之后,就通信正常了。esp8266可以正确接收到外部cpu发过来的32bytes数据。
CS--------CS
MOSI--------MOSI
MISO--------MISO
CLK--------CLK
但是我把MOSI和MISO交叉接了,即主机MOSI接了从机的MISO,而主机的MISO接了从机的MOSI,这是不对的。
我更换回来之后,就通信正常了。esp8266可以正确接收到外部cpu发过来的32bytes数据。
-
- Posts: 2
- Joined: Wed Aug 26, 2015 2:42 pm
Re: 关于esp8266使用hspi做从机(slave)遇到的问题
Postby Heirun » Mon May 27, 2019 5:49 pm
请问一下ESP8266的HSPI可以支持标准四线SPI吗?如果不行的话,那两个中断管脚可以设置成除GPIO0和GPIO2外其他的管脚吗?
Who is online
Users browsing this forum: No registered users and 180 guests
Login
Newbies Start Here
Are you new to ESP8266?
Unsure what to do?
Dunno where to start?
Start right here!
Latest SDK
Documentation
Complete listing of the official ESP8266 related documentation release by ESPRESSIF!
Must read here!
- All times are UTC+08:00
- Top
- Delete all board cookies
About Us
Espressif Systems is a fabless semiconductor company providing cutting-edge low power WiFi SoCs and wireless solutions for wireless communications and Internet of Things applications. We are the manufacturer of ESP8266EX.