[技术问答] AC78013 SPI读操作影响中断的实时性

[复制链接]
 楼主| zhaolei2612 发表于 2021-6-25 14:13 | 显示全部楼层 |阅读模式
AC78013 用SPI口读取W25Q16的内容(BMP资源),显示在TFT屏幕上。现在的现象是,屏幕刷新时(读取SPI时),测量频率的功能受到影响,数字会跳动较大,正常是不会跳动的。测量频率是通过定时器0定时100ms中断,IO端口开启下降沿中断,测量100ms中IO端口的中断次数来计算的。
SPI的代码如下
  1. /**
  2. * [url=home.php?mod=space&uid=555622]@prototype[/url] SPI_ParaInit(void)
  3. *
  4. * @param[in] void
  5. * @return         void
  6. *
  7. * [url=home.php?mod=space&uid=247401]@brief[/url]           初始化SPI.
  8. */
  9. void SPI_ParaInit(void)
  10. {
  11.         SPI_ConfigType spiConfig;
  12.        
  13.         /*清零配置结构体变量.*/
  14.         memset(&spiConfig, 0x00, sizeof(spiConfig));
  15.        
  16.         /*初始化SPI参数,波特率 = 12Mbps = (F_BCLK / (SCK_LOW+1 + SCK_HIGH+1)).*/
  17.         spiConfig.csSetup = 1;/*片选建立时间  = (CS_SETUP + 1) * CLK_PERIOD.*/
  18.         spiConfig.csHold  = 1;/*片选保持时间  = (CS_HOLD + 1) * CLK_PERIOD.*/
  19.         spiConfig.sckHigh = 1;/*SCK高电平时间 = (SCK_HIGH + 1) * CLK_PERIOD.*/
  20.         spiConfig.sckLow  = 1;/*SCK低电平时间 = (SCK_LOW + 1) * CLK_PERIOD.*/
  21.         spiConfig.csIdle  = 1;/*两条数据间最短时间间隔 = (CS_IDLE + 1) * CLK_PERIOD.*/
  22.         spiConfig.mode                   = SPI_MASTER;//设置为主机模式
  23.         spiConfig.cpha                         = SPI_CPHA_2EDGE;//设置数据采样相位,第2个边沿采样数据
  24.         spiConfig.cpol                         = SPI_CPOL_HIGH;//设置SCK空闲时极性,空闲时SCK为低
  25.         spiConfig.frmSize                 = SPI_FRAME_SIZE_8BITS;
  26.         spiConfig.rxMsbFirstEn        = ENABLE;//选择从最高位开始接收
  27.         spiConfig.txMsbFirstEn        = ENABLE;//选择从最高位开始发送
  28.         spiConfig.csOutputEn        = DISABLE;//CS有SPI硬件控制
  29.         spiConfig.continuousCSEn= ENABLE;//片选连续模式
  30.         spiConfig.dmaRxEn                = DISABLE;//禁止使用DMA接收数据
  31.         spiConfig.dmaTxEn                = DISABLE;//禁止使用DMA发送数据
  32.         spiConfig.modeFaultEn        = DISABLE;//模式故障禁止
  33.         spiConfig.wakeUpEn                = DISABLE;//主机模式不支持唤醒功能
  34.         spiConfig.spiEn                 = ENABLE;
  35.         spiConfig.callBack                = NULL;
  36.         spiConfig.interruptEn                = DISABLE;//禁止NVIC中断
  37.         spiConfig.txUFInterruptEn         = DISABLE;//禁止TXUF中断,
  38.         spiConfig.rxOFInterruptEn         = DISABLE;//禁止RXOF中断,
  39.         spiConfig.modeFaultInterruptEn = DISABLE;//模式故障中断
  40.         SPI_Init(SPI0, &spiConfig);
  41. }

  42. /**
  43. * @prototype SPI_FlashRead(uint32_t u32Addr,uint16_t* pu32Buf,uint32_t u32Cnt)
  44. *
  45. * @param[in] u32Addr: 需要读取位置的起始地址
  46. * @param[in] p32Buf: 数据读取到指针pu32Buf指向的地址
  47. * @param[in] u32Cnt: 需要读取数据长度,单位byte
  48. * @return         void
  49. *
  50. * @brief           读取spi_flash的内容
  51. */
  52. void SPI_FlashRead(uint32_t u32Addr,uint16_t* pu32Buf,uint32_t u32Cnt)
  53. {
  54.         uint16_t tx_buff[2];
  55.         tx_buff[0]=(uint16_t)((0x03<<8)|(u32Addr>>16));
  56.         tx_buff[1]=(uint16_t)(u32Addr);
  57.         SPI_CS_L;
  58.         SPI_SetFRMSize(SPI0,SPI_FRAME_SIZE_16BITS);
  59.         SPI_TransmitPoll(SPI0,(uint8_t*)tx_buff,4);
  60.         SPI_ReceivePoll(SPI0,(uint8_t*)pu32Buf,u32Cnt);
  61.         SPI_CS_H;
  62. }

定时器0的代码如下
  1. void TMR0_Init(void)
  2. {
  3.         TIMER_ConfigType tmrConfig;
  4.         memset(&tmrConfig,0x00,sizeof(tmrConfig));
  5.        
  6.         /*配置定时器.*/
  7.         tmrConfig.linkModeEn=DISABLE;
  8.         tmrConfig.interruptEn=ENABLE;       
  9.         tmrConfig.periodValue=Delay100ms;
  10.         tmrConfig.timerEn=ENABLE;
  11.         tmrConfig.callBack=TMR0_CallBack;
  12.         TIMER_Init(TIMER_CHANNEL0, &tmrConfig);
  13. }

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

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

  5. void TMR0_CallBack(void *device, uint32_t wpara, uint32_t lpara)
  6. {
  7.         uint32_t ulDat=0,ulDat1=0;
  8.         Timer0_TaskA++;//主循环用0.5S
  9.         Timer0_TaskB++;//CAN超时用
  10.        
  11.         ulDat=Eint_Cnt;
  12.         ulDat1=130*5;
  13.         Eint_Cnt=0;
  14.         ulDat=ulDat*2712/ulDat1;
  15.         if(ulDat>2712)
  16.                 ulDat=2712;
  17.         Eint_Espeed=ulDat;//Eint_Espeed为需要的结果
  18. }

现在的现象就是,调用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操作函数
  1. static void TFT_WrData8(uint8_t data)
  2. {
  3.         TFT_DATA(data);
  4.         TFT_RS_H;
  5.         TFT_WR_L;
  6.         //__nop();
  7.         TFT_WR_H;
  8. }

  9. static void TFT_WrData16(uint16_t data)
  10. {
  11.         uint8_t i=0;
  12.         i=(uint8_t)(data>>8);
  13.         TFT_DATA(i);
  14.         TFT_RS_H;
  15.         TFT_WR_L;
  16.         //__nop();
  17.         TFT_WR_H;
  18.         i=(uint8_t)data;
  19.         TFT_DATA(i);
  20.         TFT_RS_H;
  21.         TFT_WR_L;
  22. //        __nop();
  23.         TFT_WR_H;
  24. }

  25. static void TFT_WrReg(uint8_t data)
  26. {
  27.         TFT_DATA(data);
  28.         TFT_RS_L;
  29.         TFT_WR_L;
  30. //        __nop();
  31.         TFT_WR_H;
  32. }

  33. static void TFT_SetWindows(uint16_t xStar,uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
  34. {
  35.         TFT_WrReg(0X2A);
  36.         TFT_WrData8(xStar>>8);
  37.         TFT_WrData8(xStar&0x00ff);
  38.         TFT_WrData8(xEnd>>8);
  39.         TFT_WrData8(xEnd&0x00ff);
  40.         TFT_WrReg(0X2B);
  41.         TFT_WrData8(yStar>>8);
  42.         TFT_WrData8(yStar&0x00ff);
  43.         TFT_WrData8(yEnd>>8);
  44.         TFT_WrData8(yEnd&0x00ff);
  45.         TFT_WrReg(0X2C);
  46. }
  47. static void TFT_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
  48. {
  49.         uint16_t i,j;
  50.         TFT_SetWindows(sx,sy,ex,ey);
  51.         for(i=sx;i<=ex;i++)
  52.         {
  53.                 for(j=sy;j<=ey;j++)
  54.                         TFT_WrData16(color);
  55.         }
  56. }
  57. static void TFT_DrawNum48(uint16_t x,uint16_t y,uint8_t num,uint8_t color)
  58. {
  59.         uint16_t i,j;
  60.        
  61.         TFT_SetWindows(x,y,x+31,y+47);
  62.         for(i=0;i<48;i++)
  63.         {
  64.                 //SPI_FlashRead(HD_Number+122880+i*640+num*64-color*30720,Flash_Buffer.L,64);
  65.                 for(j=0;j<32;j++)
  66.                         TFT_WrData16(Flash_Buffer.L[j]);
  67.         }
  68. }

  69. TFT_DrawWT函数为最终调用函数,在主循环中,值更改时调用,调用就影响频率
  70. void TFT_DrawWT(uint32_t dat)
  71. {
  72.         uint16_t x = 202;
  73.         uint16_t y = 58;
  74.         if(dat<40)
  75.                 dat=0;
  76.         else
  77.                 dat-=40;
  78.         if(dat>999)//范围限制
  79.                 dat=999;
  80.        
  81.         if(dat<10)
  82.         {
  83.                 TFT_Fill(x,y,x+31,y+47,BLACK);
  84.                 TFT_Fill(x+32,y,x+63,y+47,BLACK);
  85.                 TFT_DrawNum48(x+32*2,y,dat,0);
  86.         }
  87.         else if(dat<100)
  88.         {
  89.                 TFT_Fill(x,y,x+31,y+47,BLACK);
  90.                 TFT_DrawNum48(x+32,y,dat/10,0);
  91.                 TFT_DrawNum48(x+32*2,y,dat%10,0);
  92.         }
  93.         else
  94.         {
  95.                 TFT_DrawNum48(x,y,dat/100,0);
  96.                 TFT_DrawNum48(x+32,y,dat%100/10,0);
  97.                 TFT_DrawNum48(x+32*2,y,dat%10,0);
  98.         }
  99. }
 楼主| zhaolei2612 发表于 2021-6-28 15:01 | 显示全部楼层
  1. #define TFT_RESET_H SET_BIT32(GPIOB_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
  2. #define TFT_RESET_L SET_BIT32((GPIOB)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
  3. #define TFT_WR_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
  4. #define TFT_WR_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
  5. #define TFT_RD_H SET_BIT32(GPIOB_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN7))
  6. #define TFT_RD_L SET_BIT32((GPIOB)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN7))
  7. #define TFT_RS_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN9))
  8. #define TFT_RS_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN9))
  9. #define TFT_DATA(m) {SET_BIT32(GPIOC->BRR,0xff);SET_BIT32(GPIOC_BSRR,(m));}//BUG? GPIOx->BRR,GPIOx_BSRR
RunningX 发表于 2021-6-28 19:16 | 显示全部楼层
从最新的描述看,其实影响频率测试的是GPIO操作?跟SPI没有关系?

评论

@zhaolei2612 :GPIO端口操作应该也不会影响中断,建议简化程序测试一下。  发表于 2021-6-29 17:55
是的。  发表于 2021-6-29 08:52
 楼主| zhaolei2612 发表于 2021-7-1 09:29 | 显示全部楼层
写了测试程序。
IO中断配置:
  1.         /*ESPEED IN端口*/
  2.         GPIO_SetFunc(GPIOB,GPIO_PIN11,GPIO_FUN0);
  3.         GPIO_SetDir(GPIOB,GPIO_PIN11,GPIO_IN);
  4.         GPIO_EnableExtInterrupt(GPIOB,GPIO_PIN11,EXTI_TRIGGER_FALLING);
  5.         GPIO_SetCallback(GPIO_PIN11,EXTI_PIN11_CallBack);
  6.         NVIC_SetPriority(EXTI9_15_IRQn,0);

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


宏定义:
  1. #define SPI_RCK_PORT                        (GPIOB)
  2. #define SPI_RCK_PIN                        (GPIO_PIN6)
  3. #define SPI_RCK_H GPIO_SetPinBit(SPI_RCK_PORT,SPI_RCK_PIN)
  4. #define SPI_RCK_L GPIO_ResetPinBit(SPI_RCK_PORT,SPI_RCK_PIN)
  5. #define SPI_RCK_TOGGLE do{if(GPIO_GetPinLevel(SPI_RCK_PORT, SPI_RCK_PIN)){SPI_RCK_L;}else{SPI_RCK_H;}}while(0)
  6. #define TFT_WR_PORT (GPIOC)
  7. #define TFT_WR_PIN (GPIO_PIN8)
  8. #define TFT_RS_PORT (GPIOC)
  9. #define TFT_RS_PIN (GPIO_PIN9)
  10. #define TFT_WR_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN8))
  11. #define TFT_WR_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN8))
  12. #define TFT_RS_H SET_BIT32(GPIOC_BSRR, GPIO_BSRR_BS_Msk(GPIO_PIN9))
  13. #define TFT_RS_L SET_BIT32((GPIOC)->BRR, GPIO_BRR_BR_Msk(GPIO_PIN9))

主程序:
  1. while(1)
  2.         {
  3.                 for(i=0;i<4000;i++)
  4.                 {
  5.                         TFT_RS_H;
  6.                         TFT_WR_L;
  7.                         TFT_WR_H;
  8.                 }
  9.         }

PB11端口接频率计,输入1KHZ. 屏蔽掉主程序,用示波器打输出波形(SPI_RCK_TOGGLE),波形如下:
4841360dd1990cb859.jpg
打开主程序,用示波器打输出波形(SPI_RCK_TOGGLE),波形如下:
3312860dd19dc4f65e.jpg
可以看出有中断丢失或相应延迟的情况,并且比较严重。具体原因还不清楚,请大佬分析一下。
问天少年 发表于 2021-7-1 16:41 | 显示全部楼层
考虑在数据量大时用DMA,这样会规避很多问题
 楼主| zhaolei2612 发表于 2021-7-1 19:40 来自手机 | 显示全部楼层
问天少年 发表于 2021-7-1 16:41
考虑在数据量大时用DMA,这样会规避很多问题

现在的测试是,主程序的IO端口操作,会影响到外部中断的响应。与是否用DMA传输数据影响不大。
caigang13 发表于 2021-7-1 21:20 来自手机 | 显示全部楼层
应该是你读操作和刷屏幕操作之间的逻辑没配合好
 楼主| zhaolei2612 发表于 2021-7-2 08:31 | 显示全部楼层
caigang13 发表于 2021-7-1 21:20
应该是你读操作和刷屏幕操作之间的逻辑没配合好

现在的测试程序是,主程序的IO端口操作,影响了外部中断的相应。和读操作,刷屏幕无关的。
skyred 发表于 2021-7-2 14:21 | 显示全部楼层
感觉,可能是逻辑时序没配合好,
这个解决起来比较慢,
 楼主| zhaolei2612 发表于 2021-7-5 09:02 | 显示全部楼层
大佬来看下哦
 楼主| zhaolei2612 发表于 2021-8-20 17:20 | 显示全部楼层
看来没有办法解决了。AC78013 的IO端口中断确实有些问题,在中断频率高一些(几百HZ)时,响应会丢失。不知道是芯片硬件问题还是软件包的问题。用过stm8s,n76e003,stm32f103,新塘M0等这些芯片都没有这些问题。找了技术支持,没有解决,说让用PWDT。哎,没想到有这种问题。希望厂家可以解释一下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

97

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部