找回密码
 立即注册
查看: 750|回复: 4

请教DMA SPI为什么会丢字节?

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:12
  • 最近打卡:2024-10-08 15:50:35

2

主题

5

回帖

138

积分

注册会员

积分
138
发表于 2024-9-23 20:42:33 | 显示全部楼层 |阅读模式
本帖最后由 llionwang 于 2024-9-23 20:48 编辑

向各位请教一个困惑了好几天的问题:

使用STC8H4K64TL-LQFP32芯片,读写W25Q32,主频为45MHz
问题现象是:
(1)不使用DMA,仅使用硬件SPI读写W25Q32,SPI为二分频,读写均正常,如下图所示:
101.png

102.png

(2)使用DMA,DMA发送数组中包括读指令和读地址,读取数据正常,如下图所示:

201.png
202.png

(3)使用独立指令发送读指令和读地址(0x03 0x00 0x00 0x00)四个字节,再使用DMA接收数据,
则会出现第二个字节会丢失,即SPI_Swap2(0x03)后面的一行不会发送出去,实际只发送了三个字节就开始DMA接收了,如下面的逻辑分析仪所示,返回的数据也是错误的
301.png


302.png



请教,会可能是哪些原因造成(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[4];
        rs[0]        =        ReadData;                //#define ReadData                     0x03    //读数据
        rs[1]        =        block_numb;        //block
        rs[2]        =        page_numb;        //page
        rs[3]        =        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[len] = SPI_Swap(0xff);
        
        W25Q_CS = 1;

        return 1;
}




补充两张图片,更清楚:
401.png
402.png


回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15613
发表于 2024-9-23 20:49:08 | 显示全部楼层
工作在 40MHz, /4 测试下
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:12
  • 最近打卡:2024-10-08 15:50:35

2

主题

5

回帖

138

积分

注册会员

积分
138
发表于 2024-9-23 20:52:25 | 显示全部楼层
神*** 发表于 2024-9-23 20:49
工作在 40MHz, /4 测试下

上面说错了,之前SPI主频一直是四分频,
刚将主频设置为40MHz、22.1184MHz,都一样丢字节
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:12
  • 最近打卡:2024-10-08 15:50:35

2

主题

5

回帖

138

积分

注册会员

积分
138
发表于 2024-9-24 17:41:34 | 显示全部楼层
问题解决了,时序混乱,现在重新写了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,不能正确读取
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:12
  • 最近打卡:2024-10-08 15:50:35

2

主题

5

回帖

138

积分

注册会员

积分
138
发表于 2024-9-26 11:29:15 | 显示全部楼层
神*** 发表于 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[256]; //_at_ DMA_TX_ADDR;
u8 xdata DmaRxBuffer[256]; //_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[20];
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[0]        =        0x03;//(u8)(0x03);                                                                //W25Q标准读指令
        dss[1]        =        0x08;//(u8)(addr>>16&0x0000FF);
        dss[2]        =        0x40;//(u8)(addr>>8&0x0000FF);
        dss[3]        =        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);
        }
}
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 02:24 , Processed in 0.136125 second(s), 74 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表