你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

CubeMX里cmsis_os的MessageQueue实现是否有bug?

[复制链接]
我是东哥 提问时间:2015-2-2 13:00 /
讨论一下CubeMX生成的cmsisi_os接口里面MessageQueue的实现,感觉上代码有bug。
MessageQueue共有三个API,osMessageCreate、osMessagePut和osMessageGet,
有疑问的在put和get上,先看put,
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)

@param  info      message information.
这个意思是MessageQueue只能传一个整数吗?如果只能传一个整数,那么创建时APIosMessageQDef_t的item_sz就必须<=4字节,这个不合理。
还是传地址?如果是地址,最好用long info啊,好吧,目前还可以正常工作。
再看实际调用FreeRTOS的地方,
中断里面调用:
    if (xQueueSendFromISR(queue_id, &info, &taskWoken) != pdTRUE) {
      return osErrorOS;
    }
普通线程里面:
    if (xQueueSend(queue_id, &info, ticks) != pdTRUE) {
      return osErrorOS;
    }
居然是传了info的指针,info是形参,取info的地址,也就是说堆栈里的一个地址,在xQueueSend里面有内存拷贝:

prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
pvItemToQueue就是&info,prvCopyDataToQueue拷贝的大小为item_sz。


同理,在osMessageGet里调用的是
xQueueReceiveFromISR(queue_id, &event.value.v, &taskWoken) 和
xQueueReceive(queue_id, &event.value.v, ticks),同样是传的堆栈里的指针,只要item_sz超过4字节,拷贝就会超出本身event所占的内存地址,程序几乎必挂。


难道说用MessageQueue只能传递一个32位的整数吗?但如果只传32位整数,那何必指定item_sz呢,api接口里面也没对这个参数检查,很容易造成内存操作异常啊,有没有哪位研究过,请指教下。

收藏 评论5 发布时间:2015-2-2 13:00

举报

5个回答
CallMeJohn 回答时间:2015-9-9 18:04:27
我也遇到了这个问题。首先定义了一个char prntBuf[64]全局,整个OS仅运行两个Task, StartDefaultTask(低优先级)和StartTask02(高优先级),设计意图是为了测试  StartTask02通过内核对象osMessage进行数据传输,向StartDefaultTask发送需要通过串口打印的信息。下面是我的相关代码:/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN 5 */       
        char* pMsg;
        uint8_t prntThs[8];
        uint8_t charNum;
        osEvent evt;

  /* Infinite loop */
  for(;;)
  {
                evt = osMessageGet(myQueue01Handle, osWaitForever);
                if(evt.status == osEventMessage){
                        pMsg = evt.value.p;
                        charNum = 4;
                        //pMsg = prntBuf;   //如果取消此注释,打印输出正常。所以我觉得是osMessage没有正常工作
                        HAL_UART_Transmit_IT(&huart2,(uint8_t*) pMsg, charNum);
                        /*  Before starting a new communication transfer, you need to check the current
                                        state of the peripheral; if it is busy you need to wait for the end of current
                                        transfer before starting a new one.
                        */
                        while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY){ }               
                }       
                else{
                        HAL_UART_Transmit_IT(&huart2, (uint8_t*)"Receive Msg Err..\r\n", 19);
                        /*  Before starting a new communication transfer, you need to check the current
                                        state of the peripheral; if it is busy you need to wait for the end of current
                                        transfer before starting a new one.
                        */
                        while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY){ }
                }
  }
  /* USER CODE END 5 */
}

/* StartTask02 function */
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  for(;;)
  {       
                strcpy(prntBuf,"");       
                strcpy(prntBuf,"Message from task02.\r\n");       
                osMessagePut(myQueue01Handle,(uint32_t)prntBuf,osWaitForever);       
                osDelay(500);   
  }
  /* USER CODE END StartTask02 */
}



========以下是讨论主题============
上述的OS指的是cmsis-rtos RTX, MDK V5环境。
有高手指点一二吗?




CallMeJohn 回答时间:2015-9-9 18:06:49
myQueue01Handle在main中,osKernelStart()开始之前已经定义。
CallMeJohn 回答时间:2015-9-10 09:17:34
我的问题已经解决,现在分享一下经验。还是上面的代码, osMessage的确已经把数据(字符串的地址)传了过去,但是osMessage传的是地址的时候,特别要注意,因为os的寻址是32位对齐的,所以定义Queue的时候,数据类型一定要是uint32_t才可以准确传地址。
我原先定义的Queue为,结果虽有打印输出,但是乱码:
/* definition and creation of myQueue01 */
osMessageQDef(myQueue01, 32, uint16_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);

修改为下面后,一切看似那么美好:
/* definition and creation of myQueue01 */
osMessageQDef(myQueue01, 32, uint32_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);

心得体会就是,不要轻意怀疑权威

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2 结贴奖励

查看全部评分

balabala777 回答时间:2017-12-19 10:26:19
学习了,感谢楼主
xlunchun 回答时间:2019-8-1 22:45:51
所以定义Queue的时候,数据类型一定要是uint32_t才可以准确传地址。
这句是重点。

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版