Столкнулся со следующей проблемой взаимодействия UARTа с FreeRTOS:
Внешнее устройство общается с платой под управлением FreeRTOS через шину 1Мбит через порты RXD2 и ТXD2.
Отправку данных в устройство осуществляю просто записью
Код
U2THR = что-то;
while (!(U2LSR_bit.TEMT));
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.
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); // ждем кадра данных
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
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;
}
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 байт, а потом молчок...