Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: CAN на STM32F + FreeRTOS
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Boriska
Пытаюсь обрабатывать входящие сообщения по шине CAN. Хотелось бы чтобы полученные сообщения были гарантированно обработаны, а если ресурсов не хватает, то чтобы они и не были получены.

Если в обработке прерывания просто очистить флаг прерывания и установить семафор, а чтение и очистку почтового ящика (CAN) сделать в отдельной задаче, то ничего не работает. После выхода из прерывания без установки RFOM (очистка ящика), прерывание тут же вызывается снова и задача по чтению сообщения вообще не получает управления.

А если в обработчике очистить флаг прерывания, прочитать и очистить почтовый ящик, то задача обработки получит управления, но тут может возникнуть ситуация, когда сообщение получено, прочитано, но не обработано, поскольку задаче по обработке не хватило ресурсов.
Как можно решить такую задачу?
Boriska
Вот так вот работает:
Код
static void vHandlerCANIRQ( void *pvParameters ){
    uint8_t curPacket;
    
    portBASE_TYPE xStatus;
    for(;; ){
        xStatus = xQueueReceive(xCANQueue, &curPacket, portMAX_DELAY );
        if( xStatus == pdPASS ){
             printf("Data - %d\r\n",RxMessage[curPacket].Data[0]);
                          canRxMessage[curPacket] = 0;
        }
    }
}

    void CAN1_RX0_IRQHandler(void) {
        uint8_t i=0;
        static portBASE_TYPE xHigherPriorityTaskWoken;
        xHigherPriorityTaskWoken = pdFALSE;
        
        if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)!=RESET){
            while((i<CAN_RX_QUEUE_MAX)&&(canRxMessage[i]==1)){
                i++;
            }
            
            if(i<CAN_RX_QUEUE_MAX){
                canRxMessage[i] = 1;
                CAN_Receive(CANx, CAN_FIFO0, &(RxMessage[i]));
                CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
                
                xQueueSendFromISR( xCANQueue, &i, &xHigherPriorityTaskWoken );
                if( xHigherPriorityTaskWoken != pdFALSE ){
                    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
                }
            }else{
                //Lost message
                CAN_FIFORelease(CANx, CAN_FIFO0);
                CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
            }

        }
    }


А так не хочет:
Код
static void vHandlerCANIRQ( void *pvParameters ){
    
    for(;; ){
        xSemaphoreTake( xBinarySemaphoreCAN, portMAX_DELAY );
        CAN_Receive(CANx, CAN_FIFO0, &(RxMessage));
        printf("Data - %d\r\n",RxMessage.Data[0]);
                    
    }
}

    void CAN1_RX0_IRQHandler(void) {

        static portBASE_TYPE xHigherPriorityTaskWoken;
        xHigherPriorityTaskWoken = pdFALSE;
        
        if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)!=RESET){
            CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
                
            xSemaphoreGiveFromISR( xBinarySemaphoreCAN, &xHigherPriorityTaskWoken );
            if( xHigherPriorityTaskWoken != pdFALSE ){
                portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
            }
            

        }
    }
zebrox
Задачи должны быть независимы друг от друга. Одна только принимает, другая только обрабатывает. Они вообще не должны знать о сущестровании друг друга.
У обработчика должен быть буфер входящих сообщений. Приемник в него записывает, если при записи нового сообщения буфер заполняется до определенного уровня, то это можно использовать как сигнал для увеличения приоритета обработчика, например, или генерацию аларма делать.
Boriska
Цитата(zebrox @ Apr 5 2013, 20:05) *
У обработчика должен быть буфер входящих сообщений. Приемник в него записывает, если при записи нового сообщения буфер заполняется до определенного уровня, то это можно использовать как сигнал для увеличения приоритета обработчика, например, или генерацию аларма делать.

В реализации CAN на STM32 уже есть буфер на 3 входящих сообщения (т.н. почтовые ящики). Почему бы ими не воспользоваться?
Если буфер полностью заполнен, то отправитель, при отправке очередного пакета, не получит подтверждение, что его сообщение доставлено. Это очень удобно. Почему бы этим не воспользоваться?
Повышать приоритет обработчика - не очень хороший вариант, поскольку обработка может быть ресурсоемкой и из-за нее самой и возникнет дефицит процессорного времени.
PanovAU
Цитата(Boriska @ Apr 8 2013, 03:53) *
Если буфер полностью заполнен, то отправитель, при отправке очередного пакета, не получит подтверждение, что его сообщение доставлено.

По моему, здесь вы ошибаетесь. Во первых, обычно на CAN сидят несколько узлов. И если один не выдал ACK по какой либо причине и не выдал флага ошибки, то это совсем не означает что ACK не выдаст другой узел. Во вторых, в Reference manual я не смог найти, что при переполнении FIFO флаг ACK не выставляется. Есть два режима, когда в конце очереди всегда самое новое сообщение (затирает предыдущее), либо очередь блокируется и новые сообщения в нее не попадают.

Цитата
Overrun
Once the FIFO is in pending_3 state (i.e. the three mailboxes are full) the next valid
message reception will lead to an overrun and a message will be lost. The hardware
signals the overrun condition by setting the FOVR bit in the CAN_RFR register. Which
message is lost depends on the configuration of the FIFO:
● If the FIFO lock function is disabled (RFLM bit in the CAN_MCR register cleared) the
last message stored in the FIFO will be overwritten by the new incoming message. In
this case the latest messages will be always available to the application.
● If the FIFO lock function is enabled (RFLM bit in the CAN_MCR register set) the most
recent message will be discarded and the software will have the three oldest messages
in the FIFO available.


Поправьте, если не прав.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.