OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2353|回复: 2

STM32F1 FSMC 和 TIM2同时启用,为什么会卡死崩溃?

[复制链接]

2

主题

8

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2020-1-19
在线时间
11 小时
发表于 2020-2-12 02:13:25 | 显示全部楼层 |阅读模式
1金钱
大家好,刚刚在测试7"的MCU TFT屏的时候,发现如下问题,还望各位大佬帮忙看下可能是什么原因(相关代码附在最后了)

STM32F103ZET6 + ALIENTEK 7" TFTLCD MODULE + JLink

问题发生过程描述(下述过程中,硬件未做任何变动):
1、使用FSMC驱动TFT屏幕,已完成。能够正常显示/刷新等。使用的是Bank1,NE1,A16作为RS线。
2、能正常驱动后,想测试一下刷新帧率(后来掐秒表测试实际12.5fps),于是初始化了一个定时器TIM2(先试了TIM2,后测试了TIM3,都不行)用来计时:方法是,使用一个全局变量,定时器每1ms对其+1。(对定时器进行了封装,该代码在之前多次测试中均正常工作。)
3、TIM2初始化放在TFT初始化后面,TFT能正常工作,但是TIM2进不了中断。
4、将TIM2初始化放在TFT初始化前面,TIM2能正常初始化,能正常进中断,GPIO和FSMC的外设能正常初始化,但是卡在了TFT的初始化上(TFT->Register = TFT_SSD1963_PLLMn_Set; TFT->Data = 0x1D;卡在了后面这句上)
5、单步调试卡在TFT->Data = 0x1D;上时,STM32好像直接复位了(硬件故障中断?总线故障中断?)。然后JLink连接就中断了,所以后续什么情况也不太清楚。而且,下次下载程序/调试前,STM32必须要断开电源,重新上电才可以,否则会报找不到CortexM设备。


相关代码:
GPIO+FSMC外设初始化代码(正常运行):

  1.         // 时钟/IO口使能/配置
  2.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
  3.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | GPIO2Rcc(GPIO_RST), ENABLE);

  4.         // PD 复用推挽输出,50MHz
  5.         // D15,D14,  ,  ,D11,D10,D9,D8 | D7,  ,D5,D4,  ,  , D1,D0
  6.         GPIOD->CRH &= 0x00FF0000;
  7.         GPIOD->CRH |= 0xBB00BBBB;
  8.         GPIOD->CRL &= 0x0F00FF00;
  9.         GPIOD->CRL |= 0xB0BB00BB;
  10.         // PE 复用推挽输出,50MHz
  11.         // E15,E14,E13,E12,E11,E10,E9,E8 | E7,,,,,,,
  12.         GPIOE->CRH &= 0x00000000;
  13.         GPIOE->CRH |= 0xBBBBBBBB;
  14.         GPIOE->CRL &= 0x0FFFFFFF;
  15.         GPIOE->CRL |= 0xB0000000;

  16.         // 复位引脚,推挽输出,50MHz
  17.         // Pin0 ~ Pin7
  18.         if (PinNo_RST < GPIO_Pin_8) {
  19.                 for (unsigned int i = 0; i < 8; ++i)
  20.                 {
  21.                         if (1 << i == PinNo_RST) {
  22.                                 // 0011,推挽输出,50MHz
  23.                                 GPIO_RST->CRL &= ~(0x0F << (i << 2));
  24.                                 GPIO_RST->CRL |= 0x03 << (i << 2);
  25.                                 RST_Pin = i;
  26.                                 break;
  27.                         }
  28.                 }
  29.         }
  30.         // Pin8 ~ Pin15
  31.         else {
  32.                 unsigned short pin = PinNo_RST >> 8;
  33.                 for (unsigned int i = 0; i < 8; ++i)
  34.                 {
  35.                         if (1 << i == pin) {
  36.                                 // 0011,推挽输出,50MHz
  37.                                 GPIO_RST->CRH &= ~(0x0F << (i << 2));
  38.                                 GPIO_RST->CRH |= 0x03 << (i << 2);
  39.                                 RST_Pin = i + 8;
  40.                                 break;
  41.                         }
  42.                 }
  43.         }
  44.         TFT_RSTo = 1;

  45.         // FSMC寄存器配置
  46.         FSMC_NORSRAMInitTypeDef FSMC_InitStruct;
  47.         FSMC_NORSRAMTimingInitTypeDef FSMC_ReadTiming, FSMC_WriteTiming;

  48.         FSMC_ReadTiming.FSMC_AddressSetupTime = 1;                        // 地址建立时间
  49.         FSMC_ReadTiming.FSMC_AddressHoldTime = 0;                        // 地址保持时间
  50.         FSMC_ReadTiming.FSMC_DataSetupTime = 15;                        // 数据建立时间
  51.         FSMC_ReadTiming.FSMC_DataLatency = 0;                                // 数据保持时间
  52.         FSMC_ReadTiming.FSMC_BusTurnAroundDuration = 0;                // 总线恢复时间
  53.         FSMC_ReadTiming.FSMC_CLKDivision = 0;                                // 时钟分频
  54.         FSMC_ReadTiming.FSMC_AccessMode = FSMC_AccessMode_A;

  55.         FSMC_WriteTiming.FSMC_AddressSetupTime = 0;                        // 地址建立时间
  56.         FSMC_WriteTiming.FSMC_AddressHoldTime = 0;                        // 地址保持时间
  57.         FSMC_WriteTiming.FSMC_DataSetupTime = 3;                        // 数据建立时间
  58.         FSMC_WriteTiming.FSMC_DataLatency = 0;                                // 数据保持时间
  59.         FSMC_WriteTiming.FSMC_BusTurnAroundDuration = 0;        // 总线恢复时间
  60.         FSMC_WriteTiming.FSMC_CLKDivision = 0;                                // 时钟分频
  61.         FSMC_WriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;

  62.         FSMC_InitStruct.FSMC_Bank = FSMC_Bank1_NORSRAM1;
  63.         FSMC_InitStruct.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;        // 地址数据总线复用
  64.         FSMC_InitStruct.FSMC_MemoryType = FSMC_MemoryType_SRAM;
  65.         FSMC_InitStruct.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
  66.         FSMC_InitStruct.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
  67.         FSMC_InitStruct.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
  68.         FSMC_InitStruct.FSMC_WrapMode = FSMC_WrapMode_Disable;
  69.         FSMC_InitStruct.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
  70.         FSMC_InitStruct.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
  71.         FSMC_InitStruct.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
  72.         FSMC_InitStruct.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
  73.         FSMC_InitStruct.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;
  74.         FSMC_InitStruct.FSMC_ReadWriteTimingStruct = &FSMC_ReadTiming;
  75.         FSMC_InitStruct.FSMC_WriteTimingStruct = &FSMC_WriteTiming;

  76.         FSMC_NORSRAMInit(&FSMC_InitStruct);
  77.         FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
复制代码

TIM2初始化代码(正常运行)
  1. <b></b><i></i><u></u><sub></sub><sup></sup><strike></strike>
  2. bool SoftTimer_Init(TIM_TypeDef* TIMx, unsigned int NVIC_PriorityGroup) {
  3.         if (!IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup))
  4.                 return false;

  5.         switch ((unsigned int)TIMx) {
  6.         case (unsigned int)TIM2:
  7.                 Rcc_Timx = RCC_APB1Periph_TIM2;
  8.                 Timx_IRQn = TIM2_IRQn;
  9.                 break;
  10.         case (unsigned int)TIM3:
  11.                 Rcc_Timx = RCC_APB1Periph_TIM3;
  12.                 Timx_IRQn = TIM3_IRQn;
  13.                 break;
  14. #if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_XL) || defined (STM32F10X_CL)
  15.         case (unsigned int)TIM4:
  16.                 Rcc_Timx = RCC_APB1Periph_TIM4;
  17.                 Timx_IRQn = TIM4_IRQn;
  18.                 break;
  19. #endif
  20. #if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_XL) || defined (STM32F10X_CL)
  21.         case (unsigned int)TIM5:
  22.                 Rcc_Timx = RCC_APB1Periph_TIM5;
  23.                 Timx_IRQn = TIM5_IRQn;
  24.                 break;
  25. #endif
  26. #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_XL) || defined (STM32F10X_CL)
  27.         case (unsigned int)TIM6:
  28.                 Rcc_Timx = RCC_APB1Periph_TIM6;
  29.                 Timx_IRQn = TIM6_IRQn;
  30.                 break;
  31.         case (unsigned int)TIM7:
  32.                 Rcc_Timx = RCC_APB1Periph_TIM7;
  33.                 Timx_IRQn = TIM7_IRQn;
  34.                 break;
  35. #endif
  36.         default:return false;
  37.         }

  38.         Timx = TIMx;

  39.         unsigned int ClkDiv = (RCC->CFGR & 0xF0) >> 4;
  40.         unsigned int psc = 1;
  41.         // AHB时钟分频器
  42.         // 0xxx: 不分频
  43.         // 1000: 2分频
  44.         // 1001: 4分频
  45.         // 1010: 8分频
  46.         // 1011: 16分频
  47.         // 1100: 64分频
  48.         // 1101: 128分频
  49.         // 1110: 256分频
  50.         // 1111: 512分频
  51.         if (ClkDiv > 0x07) {
  52.                 ClkDiv &= 0x07;
  53.                 if (ClkDiv < 4)
  54.                         psc = 0x02 << ClkDiv;
  55.                 else psc = 0x04 << ClkDiv;
  56.         }

  57.         // APB1时钟分频器
  58.         // 0xx: 不分频
  59.         // 100: 2分频
  60.         // 101: 4分频
  61.         // 110: 8分频
  62.         // 111: 16分频
  63.         ClkDiv = (RCC->CFGR & 0x00000700) >> 8;
  64.         if (ClkDiv > 0x03) {
  65.                 ClkDiv &= 0x03;
  66.                 psc <<= ClkDiv;        // 分频倍数÷2,因为“定时器时钟频&#63841;是其所在APB总线频率的两倍。然而,如果相应的APB预分频系数是1,定时器的时钟频率与所在APB总线频&#63841;一致。”
  67.         }
  68.         // 定时器输入时钟频率
  69.         psc = SystemCoreClock / psc;

  70.         // 使能时钟源
  71.         RCC_APB1PeriphClockCmd(Rcc_Timx, ENABLE);

  72.         // 配置定时器
  73.         TIM_TimeBaseInitTypeDef tim;
  74.         tim.TIM_Prescaler = 1;        //预分频系数 = 2
  75.         tim.TIM_Period = psc / 2000;        //自动装载值 = f / 2000; al * (1 / (f / (psc + 1))) = 0.001s
  76.         TIM_TimeBaseInit(TIMx, &tim);
  77.         // 清除中断
  78.         TIM_ClearFlag(TIMx, TIM_FLAG_Update);
  79.         // 开启计数器中断
  80.         TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);
  81.         // 使能计数器
  82.         TIM_Cmd(Timx, ENABLE);
  83.         //// 暂时关闭定时器的时钟,等待使用
  84.         //RCC_APB1PeriphClockCmd(Rcc_Timx, DISABLE);

  85.         // 中断配置
  86.         NVIC_InitTypeDef Nvic;
  87.         // 设置中断组
  88.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup);
  89.         // 设置中断来源
  90.         Nvic.NVIC_IRQChannel = Timx_IRQn;
  91.         // 设置抢占优先级为 2
  92.         Nvic.NVIC_IRQChannelPreemptionPriority = 2;
  93.         // 设置主优先级为 0
  94.         Nvic.NVIC_IRQChannelSubPriority = 0;
  95.         Nvic.NVIC_IRQChannelCmd = ENABLE;
  96.         NVIC_Init(&Nvic);

  97.         return true;
  98. }
复制代码

TFT初始化代码(节选部分):

  1.         // TFT配置
  2.         //u16 i = 0;
  3.         // 复位
  4.         TFT_RSTo = 0;
  5.         DelayMs(100);
  6.         TFT_RSTo = 1;

  7.         DelayMs(100);

  8.         TFT->Register = TFT_SSD1963_PLLMn_Set;
  9.         TFT->Data = 0x1D;                     // 先初始化定时器,就会卡死在该位置。该位置也是整个程序第一次向TFT写数据的时候(前一句写指令)。
  10.         TFT->Data = 0x02;
  11.         TFT->Data = 0x04;
  12.         DelayUs(100);

  13.         TFT->Register = TFT_SSD1963_PLL_Set;
  14.         TFT->Data = 0x01;
  15.         DelayMs(10);
复制代码

主函数初始化代码(其中使用了一个我自己封装的DebugOutput方法,用来输出调试信息。之前测试过SoftTimer和DebugOutput一起能正常使用):

  1. void SysInit(void)
  2. {
  3.         DebugOutput_InitTypeDef DebugOutput_InitStruct;

  4.         Sys_ClockInit(9);

  5.         //SoftTimer_Init(TIM3,NVIC_PriorityGroup_2);
  6.        
  7.         DebugOutput_InitStruct.USARTx = USART1;
  8.         DebugOutput_InitStruct.USART_BaudRate = 38400;
  9.         DebugOutput_InitStruct.USART_Parity = USART_Parity_No;
  10.         DebugOutput_InitStruct.USART_StopBits = USART_StopBits_1;
  11.         DebugOutput_InitStruct.USART_WordLength = USART_WordLength_8b;
  12.         DebugOutput_InitStruct.ReceiveHandler = UploadData;
  13.         DebugOutput_InitStruct.ReceiveMode = DebugInput_ReceiveMode_EachLine;

  14.         DebugOutput_Init(DebugOutput_InitStruct, NVIC_PriorityGroup_2);
  15.        
  16.         DebugOutput_WriteLine("系统时钟初始化完成!");
  17.         DebugOutput_WriteLine("调试输出模块初始化完成!");
  18.        
  19.         TFT_SSD1963_Init(GPIOA,GPIO_Pin_2);
  20.         DebugOutput_WriteLine("TFT初始化完成!");
  21.        
  22.         TFT_SSD1963_ClearScreen(Color_White_RGB565);
  23.        
  24. }
复制代码



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

8

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2020-1-19
在线时间
11 小时
 楼主| 发表于 2020-2-12 20:46:22 | 显示全部楼层
没人理只能自己顶一下,希望更多人能看到,帮忙查看一下,不胜感激!
回复

使用道具 举报

1

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
191
金钱
191
注册时间
2019-5-5
在线时间
49 小时
发表于 2020-3-22 01:55:37 来自手机 | 显示全部楼层
我记得百度里可以找到帖子找到进去错误中断之前的最后一个语录,应该能发现点问题
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-23 05:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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