Jump to content

    
Sign in to follow this  
M0HAX

Проблема с UART

Recommended Posts

Привет всем!

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

 

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

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

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

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

 

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

Share this post


Link to post
Share on other sites
Честно сказать не все ясно по коду, но:

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

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

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this