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

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管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版