Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с UART
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
M0HAX
Привет всем!
Столкнулся со следующей проблемой взаимодействия UARTа с FreeRTOS:
Внешнее устройство общается с платой под управлением FreeRTOS через шину 1Мбит через порты RXD2 и ТXD2.
Отправку данных в устройство осуществляю просто записью
Код
  U2THR = что-то;
   while (!(U2LSR_bit.TEMT));


а данные принимаю через USART2 RBR Interrupt. Это прерывание объявил как __fiq со всеми вытекающими последствиями.
Внутри этого прерывания не использую функции FreeRTOS, поэтому само прерывание не окаймляю макросами сохранения и восстановления контекста. Оно как бы должно работать вне системы.
Помимо этого, внутри ядра не использую функции типа __disable_interrupt() и __enable_interrupt(), т.к. они затрагивают fiq-прерывания, а вместо них использую __disable_irq() и __enable_irq().
Кроме этого, первой строкой при вызове irq-прерывания использую MSR CPSR_c, #146 - разрешение fiq-прерывания
Код
irq_handler:
        MSR     CPSR_c, #146
        portSAVE_CONTEXT    ;; Save the context of the current task...
        
        MVN      R0,#+255
        LDR      R0,[R0, #+0]                 ;; забираем адрес процедуры текущего активного прерываниЯ
        MOVS     R5,R0
        MOVS     R4,R5
        CMP      R4,#+0                        ;; адрес ненулевой -> переход на обработчик
        BEQ      ??irq_handler_0             ;; либо сброс прерываниЯ и выход
        MOV      LR,PC
        BX       R4                                 ;; переход на обработчик соответствующего IRQ-прерываниЯ
        B        ??irq_handler_1
??irq_handler_0:
        MVN      R0,#+255
        MOV      R1,#+0
        STR      R1,[R0, #+0]                  ;; сброс флага прерываниЯ - VICAddress = 0
??irq_handler_1:

        portRESTORE_CONTEXT        ;; Restore the context of the selected task.


Как только соберу кадр с помощью прерывания по приему UART2, то делаю внутри него же T2TCR_bit.CE = 1, чтобы вызвать прерывание от таймера(irq-прерывание), который должен уже проверить
кадр на контрольную сумму и послать FreeRTOS-сообщение задаче, которая инициировала связь со внешним устройством и ждет прихода кадра от него:
Код
  SendAddressToBus(THREBuffer[0]);                                                                                      // выставляем на шину признак адреса  
  xResult = xQueueReceive(xFlagCadrBUSQueue, &ucState, 1000);                                            // ждем кадра данных
  if (xResult != pdPASS) xResult = _TIMEOUT_ERROR; else xResult = ucState;

Так вот, после посылки адреса и признака чтения данных, внешнее устройство должно вернуть кадр данных. Но он приходит не полностью, ибо больше прерывания по приему не возникают...
Если я вместо строки
Код
xResult = xQueueReceive(xFlagCadrBUSQueue, &ucState, 1000);                                            // ждем кадра данных

вставлю while(1); и просто подожду чуть и остановлю эмулятор,то вижу,что данные пришли ВСЕ и так получается всегда.
Т.е. здесь в некачественном приеме как-то замешан FreeRTOS,но ведь я везде разрешил fiq-прерывания - что ему бы не вызваться и не принять данные.....
В чем трабл не могу понять,блин... Где косяк, об котрый надо стукнуться? Может кто подскажет?

Вот таблица векторов
Код
__vector:
        LDR   PC, [PC, #+24]               ;; Reset. Выбираем из памЯти адрес перехода
        LDR   PC, [PC, #+24]               ;; Undefined instructions
        B     vPortYieldProcessor          ;; переход на обработчик SWI(программное прерывание)
        LDR   PC, [PC, #+24]               ;; Prefetch abort
        LDR   PC, [PC, #+24]               ;; Data abort

__vector_0x14
        DC32  0                            ;; RESERVED
        LDR   PC, [PC, #+24]               ;; IRQ
        LDR   PC, [PC, #+24]               ;; FIQ

;;----------------------------------------------------------------------------------------
;; таблица адресов переходов
;;----------------------------------------------------------------------------------------
        DC32  __iar_program_start          ;; Reset
        DC32  undef_handler                ;; Undefined instructions
        DC32  0                            ;; Software interrupt (SWI/SVC)
        DC32  prefetch_handler             ;; Prefetch abort
        DC32  data_handler                 ;; Data abort
        DC32  0                            ;; RESERVED
        DC32  irq_handler                ;; IRQ
        DC32  vBUS_fiq_handler                  ;; FIQ


Вот само fiq-прерывание. За код не пинайте,ибо уже на скорую руку делал всякие извращенные изменения,не заботясь о красоте и т.п.
Код
__fiq __arm void vBUS_fiq_handler(void){
unsigned portCHAR   ucData, ucStatus, temp;

  temp = 0;
  ucStatus = U2IIR_bit.IID;
  switch (ucStatus){
   case  _CTI:
   case  _RDA:
  lll1:
           ucData = U2RBR;                    
           temp = 1;
           if ((U2LCR_bit.PS == _FORCED_1) || bAddressReceiveFlag){
            
             if (U2LCR_bit.PS == _FORCED_1){
               bAddressSendFlag = true;
               U2LCR_bit.PS = _FORCED_0;
             } else  
               bAddressReceiveFlag = false;
            
             ucCnt_RBR = 1;
             RBRBuffer[0] = ucData;
             if (U2LSR & 0x01) goto lll1;
             break;
           };  
          
           RBRBuffer[ucCnt_RBR++] = ucData;
          
           if (ucCnt_RBR == 2) ucLEN_RBR = ucData;
           if (ucCnt_RBR == (ucLEN_RBR + 3)) T2TCR_bit.CE = 1;
          
           if (U2LSR & 0x01) goto lll1;
           break;          
  };

  VICADDRESS = 0;
}


Трабл не зависит,использую ли я FIFO или нет. От него зависит только,сколько я байт получу... но не весь пакет в 64 байта - максимум приходят только первые 16 байт, а потом молчок...
M0HAX
Сделал другой проект, выкинул все лишнее, оставил только FreeRTOS и задачу и прерывания работы с UART2, через которое осуществляется связь со внешним устройством. Все упростил - результат тот же печальный. Через другой UART вывел на комп полученные данные и запустил программу на плате без эмулятора. В терминале вижу, что данные от внешнего устройства на плату с 2378 приходят все и всё. А ту же саму программу запускаю через эмулятор, то не работает прием данных от внешнего устройства - перестают возникать fiq-прерывания по приему от UART2 после того,как в программе вызовется обработчик SWI(программное прерывание), в котором происходит ручное переключение задач(например, это прерывание вызвается внутри xQueueReceive()). Причем проверял, нигде fiq-прерывания не запрещаются. Может эмулятор что-то не успевает сработать или теряет прерывания? Эмулятор IAR J-Link-ARM
kan35
Честно сказать не все ясно по коду, но:
Я бы для начала избавился от операторов goto в fiq.
Во вторых - не ясно, зачем вообще fiq? usart - медленное устройство, используйте irq. И соответственно там собирайте кадр и оттуда отправляйте в queue.

еще, в конструкциях типа:
Код
          
switch
......
        if ((U2LCR_bit.PS == _FORCED_1) || bAddressReceiveFlag){
             ...
             break;
           };

break -точно ли выходит из case а не из if?
}; - лучше без ;

PS: если количество байт всегда известно, то лучше dma использовать.
M0HAX
Цитата(kan35 @ Oct 7 2011, 08:28) *
Честно сказать не все ясно по коду, но:
Я бы для начала избавился от операторов goto в fiq.

Я ж написал, что
Цитата
. За код не пинайте,ибо уже на скорую руку делал всякие извращенные изменения, не заботясь о красоте и т.п.
Да и зря на goto так наезжаете, ибо он часто помогает избавиться от излишнего кода и не нарушает логики в данном случае.

Цитата(kan35 @ Oct 7 2011, 08:28) *
Во вторых - не ясно, зачем вообще fiq? usart - медленное устройство, используйте irq. И соответственно там собирайте кадр и оттуда отправляйте в queue.

Все irq-прерывания проходят через сохранение и восстановление контекста. Зачем мне нужны эти лишние операции, когда непонятно было успевает ли принять данные или нет система, да еще использовать внутри этого прерывания всякие функции freertos-а, да еще в конце прерывания контекст переключать из-за queue? На 1Мб usart получается не совсем медленным, однако.

Цитата(kan35 @ Oct 7 2011, 08:28) *
еще, в конструкциях типа:
Код
          
switch
......
        if ((U2LCR_bit.PS == _FORCED_1) || bAddressReceiveFlag){
             ...
             break;
           };

break -точно ли выходит из case а не из if?
}; - лучше без ;

PS: если количество байт всегда известно, то лучше dma использовать.

"break" выходит из case,однако.
";" - ну вот мне так нравится )
количество байт кадра известно становится только при приходе кадра. Да и не до dma было, ибо зачем новый геморой, когда dma еще не пользовался и не знаю, какие там косяки могут быть. Сначала так должно было заработать.
Все это,конечно,лирика, но без эмулятора работает все четко..
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.