Перейти к содержанию
    

Проблема с UART

Привет всем!

Столкнулся со следующей проблемой взаимодействия 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 байт, а потом молчок...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал другой проект, выкинул все лишнее, оставил только FreeRTOS и задачу и прерывания работы с UART2, через которое осуществляется связь со внешним устройством. Все упростил - результат тот же печальный. Через другой UART вывел на комп полученные данные и запустил программу на плате без эмулятора. В терминале вижу, что данные от внешнего устройства на плату с 2378 приходят все и всё. А ту же саму программу запускаю через эмулятор, то не работает прием данных от внешнего устройства - перестают возникать fiq-прерывания по приему от UART2 после того,как в программе вызовется обработчик SWI(программное прерывание), в котором происходит ручное переключение задач(например, это прерывание вызвается внутри xQueueReceive()). Причем проверял, нигде fiq-прерывания не запрещаются. Может эмулятор что-то не успевает сработать или теряет прерывания? Эмулятор IAR J-Link-ARM

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Честно сказать не все ясно по коду, но:

Я бы для начала избавился от операторов goto в fiq.

Во вторых - не ясно, зачем вообще fiq? usart - медленное устройство, используйте irq. И соответственно там собирайте кадр и оттуда отправляйте в queue.

 

еще, в конструкциях типа:

           
switch
......
        if ((U2LCR_bit.PS == _FORCED_1) || bAddressReceiveFlag){
             ...
             break;
           };

break -точно ли выходит из case а не из if?

}; - лучше без ;

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Честно сказать не все ясно по коду, но:

Я бы для начала избавился от операторов goto в fiq.

Я ж написал, что

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

 

Во вторых - не ясно, зачем вообще fiq? usart - медленное устройство, используйте irq. И соответственно там собирайте кадр и оттуда отправляйте в queue.

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

 

еще, в конструкциях типа:

           
switch
......
        if ((U2LCR_bit.PS == _FORCED_1) || bAddressReceiveFlag){
             ...
             break;
           };

break -точно ли выходит из case а не из if?

}; - лучше без ;

 

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

"break" выходит из case,однако.

";" - ну вот мне так нравится )

количество байт кадра известно становится только при приходе кадра. Да и не до dma было, ибо зачем новый геморой, когда dma еще не пользовался и не знаю, какие там косяки могут быть. Сначала так должно было заработать.

Все это,конечно,лирика, но без эмулятора работает все четко..

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...