请教DMA SPI为什么会丢字节?
本帖最后由 llionwang 于 2024-9-23 20:48 编辑向各位请教一个困惑了好几天的问题:
使用STC8H4K64TL-LQFP32芯片,读写W25Q32,主频为45MHz
问题现象是:
(1)不使用DMA,仅使用硬件SPI读写W25Q32,SPI为二分频,读写均正常,如下图所示:
(2)使用DMA,DMA发送数组中包括读指令和读地址,读取数据正常,如下图所示:
(3)使用独立指令发送读指令和读地址(0x03 0x00 0x00 0x00)四个字节,再使用DMA接收数据,
则会出现第二个字节会丢失,即SPI_Swap2(0x03)后面的一行不会发送出去,实际只发送了三个字节就开始DMA接收了,如下面的逻辑分析仪所示,返回的数据也是错误的
请教,会可能是哪些原因造成(3)的现象?
其它代码如下:
void SPI_Init()
{
SPSTAT = SPIF | WCOL; //0xc0; //清除SPI状态位
SPCTL = SSIG | SPEN | MSTR |SPDHH; //0xD0
}
void SPI_Swap2(u8 out)
{
SPDAT = out;
while((SPSTAT & SPIF) == 0) ;
SPSTAT = SPIF + WCOL; //清0 SPIF和WCOL标志
}
u8 W25Q_ReadData(u8 * buf,u8 block_numb,u8 page_numb,u8 byte_addr,u16 len)
{
u16 i, rs;
rs = ReadData; //#define ReadData 0x03 //读数据
rs = block_numb; //block
rs = page_numb; //page
rs = byte_addr; //addr
W25Q_CS = 0;
for(i = 0; i < 4; i++){
SPI_Swap(rs);
}
for(i = 0; i < len; i++){
buf = SPI_Swap(0xff);
}
buf = SPI_Swap(0xff);
W25Q_CS = 1;
return 1;
}
补充两张图片,更清楚:
工作在 40MHz, /4 测试下 神农鼎 发表于 2024-9-23 20:49
工作在 40MHz, /4 测试下
上面说错了,之前SPI主频一直是四分频,
刚将主频设置为40MHz、22.1184MHz,都一样丢字节 问题解决了,时序混乱,现在重新写了SPI和DMA代码,一切正常!
我这片W25Q32不知道速度是否正常,大家参考下:
---------------------------------------------------------
标准2线模式,硬件接口,无DMA W25Q32JVSIQ(ReadData(0x03)):
六四分频@45MHz 读取128字节,耗时616us(逻辑分析仪测算)
十六分频@45MHz 读取128字节,耗时427us(逻辑分析仪测算)
四分频@45MHz 读取128字节,耗时333us(逻辑分析仪测算)
---------------------------------------------------------
标准2线模式,硬件接口+DMA, W25Q32JVSIQ(ReadData(0x03)):
四分频@45.000MHz(11.250MHz) 读取128字节,耗时131.7us(逻辑分析仪测算)
二分频@45.000MHz,,,NG,不能正确读取
二分频@35.000MHz(17.500MHz) 读取128字节,耗时110.9us(逻辑分析仪测算)
二分频@36.864MHz(18.432MHz) 读取128字节,耗时105.3us(逻辑分析仪测算)
二分频@40.000MHz,,,NG,不能正确读取
神农鼎 发表于 2024-9-23 20:49
工作在 40MHz, /4 测试下
你好,能不能再抽空帮我看看这个问题:
读W25Q,指令+地址是4个字节,DMA读128字节,用逻辑分析仪捕获应该是132个字节才对,
但实际捕获显示DMA只读取了127字节,
如果设置DMA读256字节,则实际也只读取了255字节,
能否帮忙看看是哪里有问题?
/********************************************************
标准2线_硬件SPI+DMA_新代码测试
STC8H4K64TL-LQFP32
*********************************************************/
#include "stc8h.h"
#include "stdio.h"
#include "intrins.h"
#include <string.h>
#define u8 unsigned char //1字节 0~255
#define u16 unsigned int //2字节 0~65535
sbit SPI_SCLK = P3^2;
sbit SPI_MISO = P3^3;
sbit SPI_MOSI = P3^4;
sbit SPI_CS = P3^5;
sbit W25Q_IO2 = P2^0;
sbit W25Q_IO3 = P2^1;
bit busy = 0;
void delayms(u16 count)//* n*1ms延时
{
u8 i,j;
u16 k; //u16:0-65535,最长约65秒
for(k=0;k<count;k++){
i = 44;j = 195; //1ms@45MHz
do{
while (--j);
}
while (--i);
}
}
#define SPIF 0x80 //1000 0000 SPSTAT.7
#define WCOL 0x40 //0100 0000 SPSTAT.6
void SPI_Config()
{
P_SW1 |= 0x0C;
P_SW2 |= 0x80;
SPSTAT = 0xC0; //
SPCTL = 0xD0; //B1101 0000 忽略SS引脚,使能SPI,先收发MSB,主机,
//IE2 |= 0x02; //使能SPI中断
}
void SPI_ISR()interrupt 9
{
// P_SW2 |= 0x80;
// SPCTL = 0xD0;
// SPI_CS = 1;
// busy = 0;
}
////////////////////////////////////////////////////////////
void SPI_SendByte(u8 dat)
{
SPDAT = dat;
while (!(SPSTAT & SPIF)); //等待发送完成
SPSTAT = SPIF | WCOL; //清除SPI状态位
}
void SPI_WriteNByte(u8 *dat,u8 len)
{
u8 i;
for(i=0;i<len;i++){
SPI_SendByte(dat);
}
}
//u8 SPI_Swap(u8 dat)
//{
// SPDAT = dat; //触发SPI发送数据
// while(busy);// (!(SPSTAT & 0x80)); //等待发送完成
// SPSTAT = 0xC0; //清除SPI状态位
// return SPDAT; //返回SPI数据
//}
u8 xdata DmaTxBuffer; //_at_ DMA_TX_ADDR;
u8 xdata DmaRxBuffer; //_at_ DMA_RX_ADDR;
bit DmaSPIFlag;
void DMA_SPI_Config(void)
{
P_SW2 = 0x80;
DMA_SPI_STA = 0x00; //清中断
DMA_SPI_CFG = 0xE0; //使能中断,使能接收,使能发送
DMA_SPI_AMT = 127; //设置传输总字节数:n+1
DMA_SPI_TXAH = (u8)((u16)&DmaTxBuffer >> 8); //SPI发送数据存储地址
DMA_SPI_TXAL = (u8)((u16)&DmaTxBuffer);
DMA_SPI_RXAH = (u8)((u16)&DmaRxBuffer >> 8); //SPI接收数据存储地址
DMA_SPI_RXAL = (u8)((u16)&DmaRxBuffer);
DMA_SPI_CFG2 = 0x00; //不自动控制SS脚
DMA_SPI_CR = 0x81; //使能并清除FIFO,但未激活主机或从机模式
}
void DMA_SPI_ISR() interrupt 49
{
DMA_SPI_STA = 0;
DmaSPIFlag = 0;
}
//********************************************************
u8 dss;
void main()
{
P_SW2 = 0x80;
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
W25Q_IO2 = 1; //WP
W25Q_IO3 = 1; //HOLD
EA = 1;
SPI_Config();
DMA_SPI_Config();
//W25Q_Init();
SPI_CS = 0;
SPI_SendByte(0x66);
SPI_SendByte(0x99);
SPI_CS = 1;
memset(DmaTxBuffer,0xFF,sizeof(DmaTxBuffer));
memset(DmaRxBuffer,0xFF,sizeof(DmaRxBuffer));
memset(dss,0xFF,sizeof(dss));
dss = 0x03;//(u8)(0x03); //W25Q标准读指令
dss = 0x08;//(u8)(addr>>16&0x0000FF);
dss = 0x40;//(u8)(addr>>8&0x0000FF);
dss = 0x00;//(u8)(addr&0x0000FF);;
while(1)
{
DmaSPIFlag = 1; //设置标记: 1=忙
//开始传输
SPI_CS = 0;
SPI_WriteNByte(dss,4); //先发送指令给W25Q
DMA_SPI_CR |= 0x40; //B0100 0000开始SPI_DMA主模式操作
while(DmaSPIFlag); //通信完成后DmaSPIFlag=0,,,注意,没有超时处理,此处如错误则无法返回
SPI_CS = 1;
delayms(1000);
}
}
页:
[1]