打印
[技术问答]

AC78013 SPI读操作影响中断的实时性

[复制链接]
12552|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AC78013 用SPI口读取W25Q16的内容(BMP资源),显示在TFT屏幕上。现在的现象是,屏幕刷新时(读取SPI时),测量频率的功能受到影响,数字会跳动较大,正常是不会跳动的。测量频率是通过定时器0定时100ms中断,IO端口开启下降沿中断,测量100ms中IO端口的中断次数来计算的。
SPI的代码如下
/**
* [url=home.php?mod=space&uid=555622]@prototype[/url] SPI_ParaInit(void)
*
* @param[in] void
* @return         void
*
* [url=home.php?mod=space&uid=247401]@brief[/url]           初始化SPI.
*/
void SPI_ParaInit(void)
{
        SPI_ConfigType spiConfig;
       
        /*清零配置结构体变量.*/
        memset(&spiConfig, 0x00, sizeof(spiConfig));
       
        /*初始化SPI参数,波特率 = 12Mbps = (F_BCLK / (SCK_LOW+1 + SCK_HIGH+1)).*/
        spiConfig.csSetup = 1;/*片选建立时间  = (CS_SETUP + 1) * CLK_PERIOD.*/
        spiConfig.csHold  = 1;/*片选保持时间  = (CS_HOLD + 1) * CLK_PERIOD.*/
        spiConfig.sckHigh = 1;/*SCK高电平时间 = (SCK_HIGH + 1) * CLK_PERIOD.*/
        spiConfig.sckLow  = 1;/*SCK低电平时间 = (SCK_LOW + 1) * CLK_PERIOD.*/
        spiConfig.csIdle  = 1;/*两条数据间最短时间间隔 = (CS_IDLE + 1) * CLK_PERIOD.*/
        spiConfig.mode                   = SPI_MASTER;//设置为主机模式
        spiConfig.cpha                         = SPI_CPHA_2EDGE;//设置数据采样相位,第2个边沿采样数据
        spiConfig.cpol                         = SPI_CPOL_HIGH;//设置SCK空闲时极性,空闲时SCK为低
        spiConfig.frmSize                 = SPI_FRAME_SIZE_8BITS;
        spiConfig.rxMsbFirstEn        = ENABLE;//选择从最高位开始接收
        spiConfig.txMsbFirstEn        = ENABLE;//选择从最高位开始发送
        spiConfig.csOutputEn        = DISABLE;//CS有SPI硬件控制
        spiConfig.continuousCSEn= ENABLE;//片选连续模式
        spiConfig.dmaRxEn                = DISABLE;//禁止使用DMA接收数据
        spiConfig.dmaTxEn                = DISABLE;//禁止使用DMA发送数据
        spiConfig.modeFaultEn        = DISABLE;//模式故障禁止
        spiConfig.wakeUpEn                = DISABLE;//主机模式不支持唤醒功能
        spiConfig.spiEn                 = ENABLE;
        spiConfig.callBack                = NULL;
        spiConfig.interruptEn                = DISABLE;//禁止NVIC中断
        spiConfig.txUFInterruptEn         = DISABLE;//禁止TXUF中断,
        spiConfig.rxOFInterruptEn         = DISABLE;//禁止RXOF中断,
        spiConfig.modeFaultInterruptEn = DISABLE;//模式故障中断
        SPI_Init(SPI0, &spiConfig);
}

/**
* @prototype SPI_FlashRead(uint32_t u32Addr,uint16_t* pu32Buf,uint32_t u32Cnt)
*
* @param[in] u32Addr: 需要读取位置的起始地址
* @param[in] p32Buf: 数据读取到指针pu32Buf指向的地址
* @param[in] u32Cnt: 需要读取数据长度,单位byte
* @return         void
*
* @brief           读取spi_flash的内容
*/
void SPI_FlashRead(uint32_t u32Addr,uint16_t* pu32Buf,uint32_t u32Cnt)
{
        uint16_t tx_buff[2];
        tx_buff[0]=(uint16_t)((0x03<<8)|(u32Addr>>16));
        tx_buff[1]=(uint16_t)(u32Addr);
        SPI_CS_L;
        SPI_SetFRMSize(SPI0,SPI_FRAME_SIZE_16BITS);
        SPI_TransmitPoll(SPI0,(uint8_t*)tx_buff,4);
        SPI_ReceivePoll(SPI0,(uint8_t*)pu32Buf,u32Cnt);
        SPI_CS_H;
}

定时器0的代码如下
void TMR0_Init(void)
{
        TIMER_ConfigType tmrConfig;
        memset(&tmrConfig,0x00,sizeof(tmrConfig));
       
        /*配置定时器.*/
        tmrConfig.linkModeEn=DISABLE;
        tmrConfig.interruptEn=ENABLE;       
        tmrConfig.periodValue=Delay100ms;
        tmrConfig.timerEn=ENABLE;
        tmrConfig.callBack=TMR0_CallBack;
        TIMER_Init(TIMER_CHANNEL0, &tmrConfig);
}

IO端口的配置如下
        GPIO_SetFunc(GPIOB,GPIO_PIN11,GPIO_FUN0);
        GPIO_SetDir(GPIOB,GPIO_PIN11,GPIO_IN);
        GPIO_EnableExtInterrupt(GPIOB,GPIO_PIN11,EXTI_TRIGGER_FALLING);
        GPIO_SetCallback(GPIO_PIN11,EXTI_PIN11_CallBack);

中断处理如下,频率计算也在中断中
void EXTI_PIN11_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
        Eint_Cnt++;
}

void TMR0_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
        uint32_t ulDat=0,ulDat1=0;
        Timer0_TaskA++;//主循环用0.5S
        Timer0_TaskB++;//CAN超时用
       
        ulDat=Eint_Cnt;
        ulDat1=130*5;
        Eint_Cnt=0;
        ulDat=ulDat*2712/ulDat1;
        if(ulDat>2712)
                ulDat=2712;
        Eint_Espeed=ulDat;//Eint_Espeed为需要的结果
}

现在的现象就是,调用SPI_FlashRead函数时,Eint_Espeed值会跳动。大佬来看一下哦。

使用特权

评论回复

相关帖子

沙发
zhaolei2612|  楼主 | 2021-6-28 14:53 | 只看该作者
现在发现是,只要TFT更新时,都影响频率计算,即使屏蔽掉SPI_Flash读取函数。操作TFT只是用的普通的IO控制函数。输入频率为3000HZ,抖动约为100HZ,不刷新TFT时,不抖动。

使用特权

评论回复
板凳
zhaolei2612|  楼主 | 2021-6-28 15:00 | 只看该作者
TFT操作函数
static void TFT_WrData8(uint8_t data)
{
        TFT_DATA(data);
        TFT_RS_H;
        TFT_WR_L;
        //__nop();
        TFT_WR_H;
}

static void TFT_WrData16(uint16_t data)
{
        uint8_t i=0;
        i=(uint8_t)(data>>8);
        TFT_DATA(i);
        TFT_RS_H;
        TFT_WR_L;
        //__nop();
        TFT_WR_H;
        i=(uint8_t)data;
        TFT_DATA(i);
        TFT_RS_H;
        TFT_WR_L;
//        __nop();
        TFT_WR_H;
}

static void TFT_WrReg(uint8_t data)
{
        TFT_DATA(data);
        TFT_RS_L;
        TFT_WR_L;
//        __nop();
        TFT_WR_H;
}

static void TFT_SetWindows(uint16_t xStar,uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{
        TFT_WrReg(0X2A);
        TFT_WrData8(xStar>>8);
        TFT_WrData8(xStar&0x00ff);
        TFT_WrData8(xEnd>>8);
        TFT_WrData8(xEnd&0x00ff);
        TFT_WrReg(0X2B);
        TFT_WrData8(yStar>>8);
        TFT_WrData8(yStar&0x00ff);
        TFT_WrData8(yEnd>>8);
        TFT_WrData8(yEnd&0x00ff);
        TFT_WrReg(0X2C);
}
static void TFT_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
{
        uint16_t i,j;
        TFT_SetWindows(sx,sy,ex,ey);
        for(i=sx;i<=ex;i++)
        {
                for(j=sy;j<=ey;j++)
                        TFT_WrData16(color);
        }
}
static void TFT_DrawNum48(uint16_t x,uint16_t y,uint8_t num,uint8_t color)
{
        uint16_t i,j;
       
        TFT_SetWindows(x,y,x+31,y+47);
        for(i=0;i<48;i++)
        {
                //SPI_FlashRead(HD_Number+122880+i*640+num*64-color*30720,Flash_Buffer.L,64);
                for(j=0;j<32;j++)
                        TFT_WrData16(Flash_Buffer.L[j]);
        }
}

TFT_DrawWT函数为最终调用函数,在主循环中,值更改时调用,调用就影响频率
void TFT_DrawWT(uint32_t dat)
{
        uint16_t x = 202;
        uint16_t y = 58;
        if(dat<40)
                dat=0;
        else
                dat-=40;
        if(dat>999)//范围限制
                dat=999;
       
        if(dat<10)
        {
                TFT_Fill(x,y,x+31,y+47,BLACK);
                TFT_Fill(x+32,y,x+63,y+47,BLACK);
                TFT_DrawNum48(x+32*2,y,dat,0);
        }
        else if(dat<100)
        {
                TFT_Fill(x,y,x+31,y+47,BLACK);
                TFT_DrawNum48(x+32,y,dat/10,0);
                TFT_DrawNum48(x+32*2,y,dat%10,0);
        }
        else
        {
                TFT_DrawNum48(x,y,dat/100,0);
                TFT_DrawNum48(x+32,y,dat%100/10,0);
                TFT_DrawNum48(x+32*2,y,dat%10,0);
        }
}

使用特权

评论回复
地板
zhaolei2612|  楼主 | 2021-6-28 15:01 | 只看该作者
#define TFT_RESET_H SET_BIT32(GPIOB_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
#define TFT_RESET_L SET_BIT32((GPIOB)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
#define TFT_WR_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
#define TFT_WR_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
#define TFT_RD_H SET_BIT32(GPIOB_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN7))
#define TFT_RD_L SET_BIT32((GPIOB)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN7))
#define TFT_RS_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN9))
#define TFT_RS_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN9))
#define TFT_DATA(m) {SET_BIT32(GPIOC->BRR,0xff);SET_BIT32(GPIOC_BSRR,(m));}//BUG? GPIOx->BRR,GPIOx_BSRR

使用特权

评论回复
5
RunningX| | 2021-6-28 19:16 | 只看该作者
从最新的描述看,其实影响频率测试的是GPIO操作?跟SPI没有关系?

使用特权

评论回复
评论
RunningX 2021-6-29 17:55 回复TA
@zhaolei2612 :GPIO端口操作应该也不会影响中断,建议简化程序测试一下。 
zhaolei2612 2021-6-29 08:52 回复TA
是的。 
6
zhaolei2612|  楼主 | 2021-7-1 09:29 | 只看该作者
写了测试程序。
IO中断配置:
        /*ESPEED IN端口*/
        GPIO_SetFunc(GPIOB,GPIO_PIN11,GPIO_FUN0);
        GPIO_SetDir(GPIOB,GPIO_PIN11,GPIO_IN);
        GPIO_EnableExtInterrupt(GPIOB,GPIO_PIN11,EXTI_TRIGGER_FALLING);
        GPIO_SetCallback(GPIO_PIN11,EXTI_PIN11_CallBack);
        NVIC_SetPriority(EXTI9_15_IRQn,0);

中断处理程序:
void EXTI_PIN11_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
        SPI_RCK_TOGGLE;//IO反转
}


宏定义:
#define SPI_RCK_PORT                        (GPIOB)
#define SPI_RCK_PIN                        (GPIO_PIN6)
#define SPI_RCK_H GPIO_SetPinBit(SPI_RCK_PORT,SPI_RCK_PIN)
#define SPI_RCK_L GPIO_ResetPinBit(SPI_RCK_PORT,SPI_RCK_PIN)
#define SPI_RCK_TOGGLE do{if(GPIO_GetPinLevel(SPI_RCK_PORT, SPI_RCK_PIN)){SPI_RCK_L;}else{SPI_RCK_H;}}while(0)
#define TFT_WR_PORT (GPIOC)
#define TFT_WR_PIN (GPIO_PIN8)
#define TFT_RS_PORT (GPIOC)
#define TFT_RS_PIN (GPIO_PIN9)
#define TFT_WR_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
#define TFT_WR_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
#define TFT_RS_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN9))
#define TFT_RS_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN9))

主程序:
while(1)
        {
                for(i=0;i<4000;i++)
                {
                        TFT_RS_H;
                        TFT_WR_L;
                        TFT_WR_H;
                }
        }

PB11端口接频率计,输入1KHZ. 屏蔽掉主程序,用示波器打输出波形(SPI_RCK_TOGGLE),波形如下:

打开主程序,用示波器打输出波形(SPI_RCK_TOGGLE),波形如下:

可以看出有中断丢失或相应延迟的情况,并且比较严重。具体原因还不清楚,请大佬分析一下。

使用特权

评论回复
7
问天少年| | 2021-7-1 16:41 | 只看该作者
考虑在数据量大时用DMA,这样会规避很多问题

使用特权

评论回复
8
zhaolei2612|  楼主 | 2021-7-1 19:40 | 只看该作者
问天少年 发表于 2021-7-1 16:41
考虑在数据量大时用DMA,这样会规避很多问题

现在的测试是,主程序的IO端口操作,会影响到外部中断的响应。与是否用DMA传输数据影响不大。

使用特权

评论回复
9
caigang13| | 2021-7-1 21:20 | 只看该作者
应该是你读操作和刷屏幕操作之间的逻辑没配合好

使用特权

评论回复
10
zhaolei2612|  楼主 | 2021-7-2 08:31 | 只看该作者
caigang13 发表于 2021-7-1 21:20
应该是你读操作和刷屏幕操作之间的逻辑没配合好

现在的测试程序是,主程序的IO端口操作,影响了外部中断的相应。和读操作,刷屏幕无关的。

使用特权

评论回复
11
skyred| | 2021-7-2 14:21 | 只看该作者
感觉,可能是逻辑时序没配合好,
这个解决起来比较慢,

使用特权

评论回复
12
zhaolei2612|  楼主 | 2021-7-5 09:02 | 只看该作者
大佬来看下哦

使用特权

评论回复
13
zhaolei2612|  楼主 | 2021-8-20 17:20 | 只看该作者
看来没有办法解决了。AC78013 的IO端口中断确实有些问题,在中断频率高一些(几百HZ)时,响应会丢失。不知道是芯片硬件问题还是软件包的问题。用过stm8s,n76e003,stm32f103,新塘M0等这些芯片都没有这些问题。找了技术支持,没有解决,说让用PWDT。哎,没想到有这种问题。希望厂家可以解释一下。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

97

帖子

0

粉丝