shipeng 发表于 2023-12-21 21:24

FreeRTOS中的互斥锁在中断中Give

<p>新手第一次使用FreeRTOS的互斥锁,本想用它来指示串口发送DMA的占用情况,在DMA传输完成中断中Give串口发送DMA互斥量(xSemaphoreGiveFromISR)。结果系统始终无法正常运行起来。由于一次修改了多处代码一时定位不到问题点。只知道调试串口打印出&ldquo;FreeRTOS assert &quot;!( ( pxQueue-&gt;uxQueueType == queueQUEUE_IS_MUTEX ) &amp;&amp; ( pxQueue-&gt;u.xSemaphore.xMute...&rdquo;的消息。网上找了一圈,发现大家都说FreeRTOS的互斥锁功能不完整,本来互斥量应该遵循谁上锁谁解锁的原则,结果FreeRTOS却没能实现这个功能,他的互斥锁上锁后所有人都可以解锁。于是我便坚定了中断中也可以解锁互斥量。但是一通折腾下来始终不能成功运行,最后无意中看到宏&ldquo;xSemaphoreGiveFromISR&rdquo;的使用前注释才发现了问题所在:</p>

<p>&nbsp;</p>

<p>Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())&nbsp;must not be used with this macro.</p>

<p>原来虽然FreeRTOS不能实现谁上锁谁开锁这个功能,但是他还是稍微做了下弥补,那就是中断函数中不允许Give互斥量。</p>

Jacktang 发表于 2023-12-22 07:31

<p>FreeRTOS不能实现谁上锁谁开锁这个功能,但是他还是稍微做了下弥补,那就是中断函数中不允许Give互斥量</p>

<p>非常感谢分享</p>

jobszheng5 发表于 2023-12-22 09:48

<p>我对FreeRTOS中的互斥锁的理解也不深。</p>

<p>看来未来也需要加强一下</p>

lugl4313820 发表于 2023-12-23 10:15

现在最新版的好象说修复了这个问题,楼主可以去试试。

shipeng 发表于 2023-12-23 17:09

本帖最后由 shipeng 于 2023-12-23 17:14 编辑

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3288655&amp;ptid=1267712" target="_blank"><font color="#999999">lugl4313820 发表于 2023-12-23 10:15</font></a></font> 现在最新版的好象说修复了这个问题,楼主可以去试试。</blockquote>
</div>

<p>不知道我用的是不是最新版,总之用了互斥量就一堆的问题,各种报Assert错误,我也不知道是不是因为谁上锁谁解锁的原因导致的。总之如果遵循谁上锁谁解锁的原则使用互斥量就可以运行。否则就会报各种ASSERT错误。如果把互斥量换成二值信号量就没有这个问题。</p>

<p>下面是我的源码,说一下我的软件逻辑:每次DMA传输完成后启动一个10毫秒定时器,在定时器回调函数中Give互斥量。从而保证帧最小间隔为10毫秒,以防止发送帧粘连。</p>

<pre>
<code class="language-cpp">SemaphoreHandle_t DMA2C5MuxSem_Handle = NULL;

TimerHandle_t xHandleTimerU4Tx = NULL;

TaskHandle_t xHandleTaskU4TX = NULL;

static void U4TxTimerCallback(void);
static void CreateU4TxFrameDelay(TickType_t xTimerPeriodInTicks );
static void vTaskU4TX_Handler(void *pvParameters);
void UART4_DMA_Init(void);
void BSP_UART4_Init(void);

void BSP_USART_Config(void)
{
        BSP_UART4_Init();
        UART4_DMA_Init();
        NVIC_EnableIRQRequest(UART4_IRQn, 2, 0);
        USART_EnableInterrupt(UART4, USART_INT_IDLE);
        /* Enable UART4 RX and UART4 TX DMA */
        USART_EnableDMA(UART4, USART_DMA_TX_RX);
        U4RxQueue = xQueueCreate(U4RX_QUE_DEPTH, U4RX_QUE_SIZE);//msgs , length of msg(byte)
        if (NULL==U4RxQueue)printf("U4RxQueue Creating Failed!\r\n");
        U4TxQueue = xQueueCreate(4, 4);
        if (NULL==U4TxQueue)printf("U4TxQueue Creating Failed!\r\n");
        #ifndef        USE_DMA_WITH_MUTEX
        DMA2C5MuxSem_Handle = xSemaphoreCreateBinary();
        #else
        DMA2C5MuxSem_Handle = xSemaphoreCreateMutex();
        #endif
        if (NULL==DMA2C5MuxSem_Handle)printf("DMA2C5MuxSem Creating Failed!\r\n");
        #ifndef        USE_DMA_WITH_MUTEX
        else if (0==uxSemaphoreGetCount(DMA2C5MuxSem_Handle) &amp;&amp; pdPASS!=xSemaphoreGive(DMA2C5MuxSem_Handle))printf("DMA2C5MuxSem Giving Failed!\r\n");
        #endif
        CreateU4TxFrameDelay(10);
        xTaskCreate((TaskFunction_t )vTaskU4TX_Handler,
                                                        (const char*    )"UART4 TX Task",
                                                        (uint16_t       )256,
                                                        (void*          )NULL,
                                                        (UBaseType_t    )5,
                                                        (TaskHandle_t*)&amp;xHandleTaskU4TX);

}

static void U4TxTimerCallback(void)
{
        #ifndef        USE_DMA_WITH_MUTEX
        if (0==uxSemaphoreGetCount(DMA2C5MuxSem_Handle) &amp;&amp; pdPASS != xSemaphoreGive( DMA2C5MuxSem_Handle))printf("DMA2C5MuxSem Giving failed!");
        #else
        if (NULL!=xSemaphoreGetMutexHolder(DMA2C5MuxSem_Handle) &amp;&amp; pdPASS != xSemaphoreGive( DMA2C5MuxSem_Handle))printf("DMA2C5MuxSem Giving failed!");
        #endif
        else if (0!=uxQueueMessagesWaiting(U4TxQueue))portYIELD();//if the queue is not empty,then request a context switch
}

static void CreateU4TxFrameDelay(TickType_t xTimerPeriodInTicks )
{
        xHandleTimerU4Tx = xTimerCreate("U4TxTimer",xTimerPeriodInTicks,pdFALSE,(void*)3,(TimerCallbackFunction_t)U4TxTimerCallback);
        if (NULL==xHandleTimerU4Tx)printf("U4TxTimer Creating failed!");
}

static void vTaskU4TX_Handler(void *pvParameters)
{
        UsartTxRxBuffer_t *tx_buffer;
        while(1)
        {
                if (pdPASS==xQueueReceive(U4TxQueue, (uint8_t*)&amp;tx_buffer, portMAX_DELAY))
                {
                        xSemaphoreTake(DMA2C5MuxSem_Handle, 5689U);//5689ms Is The MAXTIME of DMA-UART-Tx,65536bytes*1000ms/11520(byte rate)=5688.888...
                        if (0!=tx_buffer-&gt;length)
                        {
                                /* Disable TX DMA */
                                DMA_Disable(DMA2_Channel5);
                                memcpy(DMA_UART4_TxBuf,tx_buffer-&gt;DatArea,tx_buffer-&gt;length);
                                DMA2_Channel5-&gt;CHNDATA_B.NDATA = tx_buffer-&gt;length;
                                /* Enable TX DMA */
                                DMA_Enable(DMA2_Channel5);
                        }
                        if (NULL!=tx_buffer)vPortFree((uint8_t*)tx_buffer);
                }
        }
}

void DMA2_Channel5_IRQHandler(void)
{
        if (RESET != DMA_ReadIntFlag(DMA2_INT_FLAG_TC5))
        {
                BaseType_t xHigherPriorityTaskWoken = pdFALSE;
                DMA_ClearIntFlag(DMA2_INT_FLAG_TC5);
                if (NULL!=xHandleTimerU4Tx)
                {
                        xTimerResetFromISR(xHandleTimerU4Tx,&amp;xHigherPriorityTaskWoken);
                }
        }
}

void UART4_DMA_Init(void)
{
        DMA_Config_T dmaConfig;

        /* Enable DMA Clock */
        RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA2);

        /* TX DMA config */
        dmaConfig.peripheralBaseAddr = UART4_DR_ADDRESS;
        dmaConfig.memoryBaseAddr = (uint32_t)DMA_UART4_TxBuf;
        dmaConfig.dir = DMA_DIR_PERIPHERAL_DST;
        dmaConfig.bufferSize = 0;
        dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
        dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
        dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE;
        dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE;
        dmaConfig.loopMode = DMA_MODE_NORMAL;
        dmaConfig.priority = DMA_PRIORITY_HIGH;
        dmaConfig.M2M = DMA_M2MEN_DISABLE;

        /* Enable DMA channel */
        DMA_Config(DMA2_Channel5, &amp;dmaConfig);

        /* Enable TX DMA */
        DMA_Enable(DMA2_Channel5);

        NVIC_EnableIRQRequest(DMA2_Channel5_IRQn, 3, 0);
        DMA_EnableInterrupt(DMA2_Channel5, DMA_INT_TC);

        /* RX DMA Configure */
        dmaConfig.dir = DMA_DIR_PERIPHERAL_SRC;
        dmaConfig.loopMode = DMA_MODE_CIRCULAR;
        dmaConfig.bufferSize = sizeof(DMA_UART4_RxBuf);
        dmaConfig.memoryBaseAddr = (uint32_t)DMA_UART4_RxBuf;
        /* Enable DMA channel */
        DMA_Config(DMA2_Channel3, &amp;dmaConfig);

        /* Enable RX DMA */
        DMA_Enable(DMA2_Channel3);

//        NVIC_EnableIRQRequest(DMA2_Channel3_IRQn, 1, 0);
//        DMA_EnableInterrupt(DMA2_Channel3, DMA_INT_TC);
}

void BSP_UART4_Init(void)
{
        GPIO_Config_T GPIO_ConfigStructure;
        USART_Config_T USART_ConfigStruct;

        RCM_EnableAPB2PeriphClock((RCM_APB2_PERIPH_T)(RCM_APB2_PERIPH_GPIOC));
        RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_UART4));

        /*Uart4 TX*/
        GPIO_ConfigStructure.pin = GPIO_PIN_10;
        GPIO_ConfigStructure.speed = GPIO_SPEED_50MHz;
        GPIO_ConfigStructure.mode = GPIO_MODE_AF_PP;
        GPIO_Config(GPIOC, &amp;GPIO_ConfigStructure);

        /*Uart4 RX*/
        GPIO_ConfigStructure.pin = GPIO_PIN_11;
        GPIO_ConfigStructure.mode = GPIO_MODE_IN_FLOATING;
        GPIO_Config(GPIOC, &amp;GPIO_ConfigStructure);

        USART_ConfigStruct.baudRate = 115200;
        USART_ConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
        USART_ConfigStruct.mode = USART_MODE_TX_RX;
        USART_ConfigStruct.parity = USART_PARITY_NONE;
        USART_ConfigStruct.stopBits = USART_STOP_BIT_1;
        USART_ConfigStruct.wordLength = USART_WORD_LEN_8B;
        USART_Config(UART4, &amp;USART_ConfigStruct);

        USART_Enable(UART4);

}
</code></pre>

<p>&nbsp;</p>

lugl4313820 发表于 2023-12-23 20:16

<p>前段时间管管发了一个帖子,说freertos升级到了最新版了的,你可以去看看。</p>

freebsder 发表于 2023-12-25 17:17

<p>我记得是可以的呀,应该是10版本以上。</p>

hailan365 发表于 2023-12-26 08:30

<p>同意版主大大,升级试试看</p>

<p><img _height="10" border="0" src="http://aijuanpi.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://aabbkj.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://gdmixue.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://heitimes.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://cpawhy.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://ycznzs.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://taomeibao.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://lainiaoba.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://munrak.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://xigua120.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://ryjxw.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://yushenjt.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://ykruxian.com/Photos/qoute/line.gif" width="100" /><img _height="10" border="0" src="http://ycydxl.com/Photos/qoute/line.gif" width="100" /></p>
页: [1]
查看完整版本: FreeRTOS中的互斥锁在中断中Give