STM32CubeMX----杂记

(1)在使用FSMC作为LCD接口时,同时ENABLE了FreeRTOS,发现生成的工程文件,编译之后会出问题。

STM32CubeMX----杂记_第1张图片

        STM32CubeMX----杂记_第2张图片

 

         研究后发现问题出在“FreeRTOSConfig.h”这段代码:

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
 /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
 #define configPRIO_BITS         __NVIC_PRIO_BITS
#else
 #define configPRIO_BITS         4
#endif

   当我使用了FSMC并且ENABLE 了FreeRTOS,“__NVIC_PRIO_BITS”这个宏就会被定义,此时RTOS的宏

“configPRIO_BITS”会被定义为“__NVIC_PRIO_BITS”,这个宏在“stm32f205xx.h”里面:

#define __NVIC_PRIO_BITS          4U       /*!< STM32F2XX uses 4 Bits for the Priority Levels */

也就是说“configPRIO_BITS”这个宏被定义为“4U”也就是类型为“unsigned int”的4。

我尝试在汇编函数里,直接将:

mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY

改为:

mov r0, #4U

编译出错,但如果将“4U”改为“4”是没问题的。

后记:在韦东山第一期加强版视频编写LED程序的视频有讲到,在汇编里面指令需要占据一定的位数,例如:

 

mov r0, #0x12345678

是不行的,因为“MOV”这个指令本身占据了一定的位数。而“4U“本身为32位,stm32为32位系统,所以”MOV“这个指令码被清零了。具体可以了解下机器码跟汇编。

(2)ADC采集一次信号后不再采集

        问题可以参考这个链接:http://www.ing10bbs.com/forum.php?mod=viewthread&tid=194&extra=

        除了RCC、SYS,只配置了ADC2的IN8,NVIC Settings打开ADC全局中断:

STM32CubeMX----杂记_第3张图片

  生成工程的改动很小,增加了一个ADC值获取的回调函数以及一个ADC启动的函数:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
   ADC_VAL = ADC2->DR;
}

ADC初始化里面添加了IT启动:

HAL_ADC_Start_IT(&hadc2);

然后进入仿真发现,ADC采样一次信号后,ADC2->DR寄存器里面的值不变了。研究了老半天,看了几遍参考手册中ADC寄存器的描述,怀疑是EOCS寄存器的问题。所以将:

hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

改为:

hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;

很好,ADC连续采样了。但又产生一个新的问题,程序一直重复进入ADC中断,不进入while(1);大循环了。

由此猜测,是不是因为ADC采样转化太快了,导致未处理完一次中断又产生新的中断?

又进行修改:

sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

改为:

sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;

这次可以正常运行了。其实,最好在启动ADC之后,关闭不必要的中断源,例如只需要看门狗中断:

__HAL_ADC_DISABLE_IT(&hadc2, ADC_IT_EOC|ADC_IT_JEOC|ADC_IT_OVR);

后记:在MDK仿真下观察寄存器,发现关闭中断的指令,关闭的是”ADC_IT_OVR“这个中断源。

这个是”溢出中断“的中断源。当ADC以”ADC_SAMPLETIME_3CYCLES“进行转换时,当前中断尚未处理完便再次触发中断

就会造成中断溢出。所以将ADC转换速率降低,或者关闭ADC_IT_OVR“程序可以正常运行。

(3)内部FLASH的操作

MCU是F205VCT6

1、写

//STM FLASH写函数
void STMFLASH_Write_NoCheck ( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite )   
{
        uint16_t i;        
	 
	      HAL_FLASH_Unlock();
	      __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR|FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
	
        for(i=0;i

 

写之前要去除FLASH的写保护,然后就是写函数中的清楚标志位问题。如执行了

 

HAL_FLASH_Unlock();

然后立即执行写函数,会发现第一个数据写不进FLASH,但是后续的数据是正常的。试过增加几十毫秒的延时,但是结果依旧错误。如果在写之前先清除错误标志位,则可以正常写入。

2、擦除

//STM FLASH擦除函数
void SectorErase(u32 SectorNum )  
{  
    FLASH_EraseInitTypeDef  eraseInit;  
    u32         error;  
	 
	  HAL_FLASH_Unlock();
	  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR|FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
	
	  eraseInit.Sector = SectorNum;
    eraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;   
    eraseInit.NbSectors   = 1;  
    eraseInit.VoltageRange   = FLASH_VOLTAGE_RANGE_3;
  
    if ( HAL_FLASHEx_Erase( &eraseInit, &error ) == HAL_OK )  
    {  
    }  
		HAL_FLASH_Lock();
}  

 

跟写函数一样,解锁FLASH后立即擦除,需要先清除错误标志位。

 

另外,执行擦除函数,如果是擦除0~3扇区,则可以正常进入仿真(代码在扇区0,擦除扇区0会出现异常,但确实能进入仿真的)界面。

如果擦除4~5扇区,则出现以下问题

STM32CubeMX----杂记_第4张图片

不能进入仿真,但是扇区擦除却是成功的。

尝试:

__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                           FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

(4)晶振电路出错

仿真,发现进入“ SystemClock_Config();”后,进入“void _Error_Handler(char *file, int line);”

查看电路发现晶振的电容过小,导致外部晶振不起振。

 

(5)多个中断的使能

例如需要同时启用定时器3的捕获中断以及更新中断:

  HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_3);	  //TIM3开始捕获PWM,开启捕获中断
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);       //使能TIM3更新中断

 

(6)中断中使用定时函数问题

在使用FLASH 模拟USB U盘的时候出现一个问题,我在USB调用的初始化设备函数中进行FLASH的初始化,

且初始化中有使用到延时函数:HAL_Delay(); 这导致了程序卡死在HAL_Delay();   原因是此延时函数通过系统滴答

定时器实现,而USB初始化设备是在中断中进行的,优先级USB > 系统滴答定时器。

//初始化spi flash
void FLASH_Init(void)
{

      FLASH_GPIOInit();
	  FLASH_SPIInit();
	  
	  HAL_Delay(5);
}


//此函数在中断中调用
int8_t STORAGE_Init_FS(uint8_t lun)
{
	
  FLASH_Init();
  return (USBD_OK);

}

   

(7)FATFS+FreeRTOS移植失败记录

1、刚开始移植,尝试裸机FATFS,成功。第二次移植,加上Freertos,运行一直卡死在f_open();函数里面,进入仿真

发现最后是卡死在参数检测的语句:

BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
{
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;

	
	configASSERT( pxQueue ); //卡死此处
    .....................

这是stm32cubemx种,激活FATFS与FreeRTOS后,会自动启用互斥锁。这个函数是FreeRTOS二值信号量的Release部分函数。刚开始以为是pxQueue没有成功获取地址,仿真跟踪很久发现,地址是对的,在f_open();最后,

	LEAVE_FF(dj.fs, res);

dj.fs是临时指针变量,指向我挂载器件的fs。地址是对的,fs的二值信号量指针变量sobj地址是0x20000000,传递进去之后直到:configASSERT(pxQueue);也是正确的,pxQueue = 0x20000000;

于是,怀疑是"0x20000000"这个地址本身出了问题。

2、仿真跟踪FATFS创建二值信号量代码,发现二值信号量在f_mount();中创建:

#if _FS_REENTRANT						/* Create sync object for the new volume */
		if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
#endif

此处,给fs->sobj进行赋值:

int ff_cre_syncobj (	/* TRUE:Function succeeded, FALSE:Could not create due to any error */
	BYTE vol,			/* Corresponding logical drive being processed */
	_SYNC_t *sobj		/* Pointer to return the created sync object */
)
{
  int ret;
  
  osSemaphoreDef(SEM);
  *sobj = osSemaphoreCreate(osSemaphore(SEM), 1);		
  ret = (*sobj != NULL);
  
  return ret;
}

在这里申请了一个二值信号量,且信号量句柄返回给了fs->sobj。观察此地址,发现并不是:0x20000000!!!

STM32CubeMX----杂记_第5张图片

正确地址是:0x20005390

真相出来了,导致二值信号量释放卡死的原因是信号量地址被篡改!那么,地址是在哪里被篡改的呢?

继续仿真寻找,结果发现在这里地址被改成:0x20000000了:

#if _MAX_SS != _MIN_SS						/* Get sector size (multiple sector size cfg only) */
	if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
		|| SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR;
#endif

仿真进去:

#if _USE_IOCTL == 1
DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
  switch (cmd) 
	{
		 case GET_SECTOR_COUNT: *(DWORD*)buff = FLASH_Info.BLK_NBR;  break;
		 case GET_SECTOR_SIZE:  *(DWORD*)buff = FLASH_Info.BLK_SIZ;  break;
		 case GET_BLOCK_SIZE:   *(DWORD*)buff = 1;                   break;		
	}
	
  return RES_OK;
}
#endif /* _USE_IOCTL == 1 */

#define    SS(fs)    ((fs)->ssize)    /* Variable sector size */

仔细观察,fs的指针变量ssize,发现是WORD类型

但是在移植的时候,我用了这条语句:*(DWORD*)buff = FLASH_Info.BLK_NBR;这里用到了DWORD

这样,直接改变了fs结构体中ssize的值,以及它的下一个成员sobj的值。

以上为FATFS结构体成员定义。

3、综上所述,将disk_ioctl();中的“DWORD”改成"WORD",程序成功运行!!!

     其实这个"DWORD是"参考了网上别人的代码放进去的。别人没出问题所以没发现这个错误,也有可能是以前的版本确实这个

    ssize是“DWORD”类型。以后在移植的时候,搞清楚函数形参的类型是很有必要的。

 

(8)HAL库串口中断清标志位问题

     如下代码,先清除标志位再执行arr[0]++;   数据是正常的,arr[0]每发送一次数据自增1

void USART1_IRQHandler(void)
{

    __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
    arr[0]++;	
}

    但是改成如下,arr[0]则每次自增2。也就是说进入了2次串口1中断

void USART1_IRQHandler(void)
{
    arr[0]++;	
    __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);

}

 

 

 

 

你可能感兴趣的:(STM32,C语言,HAL)