我是东哥 发表于 2015-2-2 13:00:14

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

讨论一下CubeMX生成的cmsisi_os接口里面MessageQueue的实现,感觉上代码有bug。
MessageQueue共有三个API,osMessageCreate、osMessagePut和osMessageGet,
有疑问的在put和get上,先看put,
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)

@paraminfo      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接口里面也没对这个参数检查,很容易造成内存操作异常啊,有没有哪位研究过,请指教下。

CallMeJohn 发表于 2015-9-9 18:04:27

我也遇到了这个问题。首先定义了一个char prntBuf全局,整个OS仅运行两个Task, StartDefaultTask(低优先级)和StartTask02(高优先级),设计意图是为了测试StartTask02通过内核对象osMessage进行数据传输,向StartDefaultTask发送需要通过串口打印的信息。下面是我的相关代码:/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */       
        char* pMsg;
        uint8_t prntThs;
        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);

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

balabala777 发表于 2017-12-19 10:26:19

学习了,感谢楼主:lol

xlunchun 发表于 2019-8-1 22:45:51

所以定义Queue的时候,数据类型一定要是uint32_t才可以准确传地址。
这句是重点。
页: [1]
查看完整版本: CubeMX里cmsis_os的MessageQueue实现是否有bug?