天天看點

M4和M7雙核之間消息通信

作者:嵌入式Linux

今天給大家分享的是:使用FreeRTOS消息緩沖區,實作簡單的非對稱多處理(AMP)核心到核心通信,結合STM32H7(M4和M7) 雙核處理器為例。

概述

實作STM32H7雙核之間通信是FreeRTOS官方提供的一個方案,是基于FreeRTOS消息緩沖區,該消息緩沖區是無鎖循環緩沖區,可以将大小不同的資料包從單個發送方傳遞到單個接收方。

說明,該消息緩沖區僅提供資料的傳輸,不提供通信相關協定處理。

基本原理

實作雙核之間通信基本原理:發送和接收任務位于非對稱多處理器(AMP)配置中的多核微控制器(MCU)的不同核心上,這意味着每個核心都運作自己的FreeRTOS程式。

同時,一個核心在另一個核心中具有生成中斷的能力,以及兩個核心都有通路的記憶體區域(共享記憶體)。消息緩沖區以每個核心上運作在應用程式已知的位址置在共享記憶體中,如下圖:

M4和M7雙核之間消息通信

理想情況下,還将有一個記憶體保護單元(MPU),以確定隻能通過核心的消息緩沖區API來通路消息緩沖區,并最好将共享記憶體标記為不可被其他程式占用。

單消息代碼描述

這裡官方提供了實作該方案的基礎代碼(僅供參考)。

将資料發送到流緩沖區的代碼:

xMessageBufferSend()
{
    /* If a time out is specified and there isn't enough
    space in the message buffer to send the data, then
    enter the blocked state to wait for more space. */
    if( time out != 0 )
    {
        while( there is insufficient space in the buffer &&
               not timed out waiting )
        {
            Enter the blocked state to wait for space in the buffer
        }
    }


    if( there is enough space in the buffer )
    {
        write data to buffer
        sbSEND_COMPLETED()
    }
}           

從流緩沖區讀取資料的代碼:

xMessageBufferReceive()
{
    /* If a time out is specified and the buffer doesn't
    contain any data that can be read, then enter the
    blocked state to wait for the buffer to contain data. */
    if( time out != 0 )
    {
        while( there is no data in the buffer &&
               not timed out waiting )
        {
            Enter the blocked state to wait for data
        }
    }


    if( there is data in the buffer )
    {
        read data from buffer
        sbRECEIVE_COMPLETED()
    }
}           

如果任務在xMessageBufferReceive()中進入阻塞狀态以等待緩沖區包含資料,則将資料發送到緩沖區必須取消阻塞該任務,以便它可以完成其操作。

當xMessageBufferSend()調用sbSEND_COMPLETED()時,任務将不受阻礙。

M4和M7雙核之間消息通信

ISR通過将消息緩沖區的句柄作為參數傳遞給xMessageBufferSendCompletedFromISR()函數來解除對任務的阻塞。

如圖箭頭所示,其中發送和接收任務位于不同的MCU核心上:

1.接收任務嘗試從空的消息緩沖區中讀取資料,并進入阻止狀态以等待資料到達。

2.發送任務将資料寫入消息緩沖區。

3.sbSEND_COMPLETED()在正在執行接收任務的核心中觸發一個中斷。

4.中斷服務例程調用xMessageBufferSendCompletedFromISR()來解除阻止接收任務,該任務現在可以從緩沖區讀取,因為緩沖區不再為空。

多消息代碼描述

當隻有一個消息緩沖區時,很容易将消息緩沖區的句柄傳遞到xMessageBufferSendCompletedFromISR()中。

但是要考慮有兩個或更多消息緩沖區的情況,ISR必須首先确定哪個消息緩沖區包含資料。如果消息緩沖區的數量很少,則有幾種方法可以實作:

  • 如果硬體允許,則每個消息緩沖區可以使用不同的中斷線,進而使中斷服務程式和消息緩沖區之間保持一對一的映射。
  • 中斷服務例程可以簡單地查詢每個消息緩沖區以檢視其是否包含資料。
  • 可以通過傳遞中繼資料(消息是什麼,消息的預期接收者是什麼等等)以及實際資料的單個消息緩沖區來代替多個消息緩沖區。

嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和内容,導緻工資要不上去!

無償分享大家一個資料包,差不多150多G。裡面學習内容、面經、項目都比較新也比較全!某魚上買估計至少要好幾十。

點選這裡找小助理0元領取:加微信領取資料

M4和M7雙核之間消息通信
M4和M7雙核之間消息通信

但是,如果存在大量或未知的消息緩沖區,則這些技術效率不高。

在這種情況下,可伸縮的解決方案是引入單獨的控制消息緩沖區。如下面的代碼所示,sbSEND_COMPLETED()使用控制消息緩沖區将包含資料的消息緩沖區的句柄傳遞到中斷服務例程中。

使用sbSEND_COMPLETED()的實作:

/* Added to FreeRTOSConfig.h to override the default implementation. */
#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreToCoreInterrupt( pxStreamBuffer )


/* Implemented in a C file. */
void vGenerateCoreToCoreInterrupt( MessageBufferHandle_t xUpdatedBuffer )
{
size_t BytesWritten.


    /* Called by the implementation of sbSEND_COMPLETED() in FreeRTOSConfig.h.
    If this function was called because data was written to any message buffer
    other than the control message buffer then write the handle of the message
    buffer that contains data to the control message buffer, then raise an
    interrupt in the other core.  If this function was called because data was
    written to the control message buffer then do nothing. */
    if( xUpdatedBuffer != xControlMessageBuffer )
    {
        BytesWritten = xMessageBufferSend(  xControlMessageBuffer,
                                            &xUpdatedBuffer,
                                            sizeof( xUpdatedBuffer ),
                                            0 );


        /* If the bytes could not be written then the control message buffer
        is too small! */
        configASSERT( BytesWritten == sizeof( xUpdatedBuffer );


        /* Generate interrupt in the other core (pseudocode). */
        GenerateInterrupt();
    }
}           

然後,ISR讀取控制消息緩沖區以獲得句柄,将句柄作為參數傳遞到xMessageBufferSendCompletedFromISR()中:

void InterruptServiceRoutine( void )
{
MessageBufferHandle_t xUpdatedMessageBuffer;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;


    /* Receive the handle of the message buffer that contains data from the
    control message buffer.  Ensure to drain the buffer before returning. */
    while( xMessageBufferReceiveFromISR( xControlMessageBuffer,
                                         &xUpdatedMessageBuffer,
                                         sizeof( xUpdatedMessageBuffer ),
                                         &xHigherPriorityTaskWoken )
                                           == sizeof( xUpdatedMessageBuffer ) )
    {
        /* Call the API function that sends a notification to any task that is
        blocked on the xUpdatedMessageBuffer message buffer waiting for data to
        arrive. */
        xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer,
                                            &xHigherPriorityTaskWoken );
    }


    /* Normal FreeRTOS "yield from interrupt" semantics, where
    xHigherPriorityTaskWoken is initialised to pdFALSE and will then get set to
    pdTRUE if the interrupt unblocks a task that has a priority above that of
    the currently executing task. */
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}           
M4和M7雙核之間消息通信

如圖,使用控制消息緩沖區時的順序:

1.接收任務嘗試從空的消息緩沖區中讀取資料,并進入阻止狀态以等待資料到達。

2.發送任務将資料寫入消息緩沖區。

3.sbSEND_COMPLETED()将現在包含資料的消息緩沖區的句柄發送到控制消息緩沖區。

4.sbSEND_COMPLETED()在正在執行接收任務的核心中觸發一個中斷。

5.中斷服務例程從控制消息緩沖區中讀取包含資料的消息緩沖區的句柄,然後将該句柄傳遞給xMessageBufferSendCompletedFromISR()API函數以取消阻止接收任務,該任務現在可以從緩沖區讀取,因為緩沖區不再存在空的。

當然,以上僅提供基礎原理和方法,具體實作需結合項目實際情況。更多相關内容,請參看官方相關資料。

------------ END ------------

文章連結:https://mp.weixin.qq.com/s/cLHJvPrGDU0v9oLVO6DRIw

轉載自:strongerHuang 嵌入式專欄

文章來源:M4和M7雙核之間消息通信

版權申明:本文來源于網絡,免費傳達知識,版權歸原作者所有。如涉及作品版權問題,請聯系我進行删除。

繼續閱讀