|
|
  |
Keil RTX-kernel и прием/передача по UART, Как лучше организовать взаимодействие? |
|
|
|
Feb 27 2011, 14:40
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-03-07
Пользователь №: 25 855

|
Доброго времени суток! Есть проект с использованием RTX-kernel. Нужно организовать прием/передачу данных по UART. Т.к. скорости маленькие 4800/9600, то хочется снизить время бесполезного простоя системы в ожидании готовности приемника или передатчика - есть масса другой работы по обработке данных. Вот раздумываю как это сделать правильнее, красивее, с точки зрения RTOS.
С приемом, в общем, более-менее понятно. Включены прерывания по приему символа (ПДП пока не используется) и в обработчике принятый символ через mailbox отправляется задаче обрабатывающей прием.
Передачу, на данный момент сделал так: Разрешил прерывания по готовности передатчика, в обработчике прерывания устанавливается событие "передатчик готов", а уже задача, ответственная за передачу, по этому событию пишет данные в буфер UART'a. Минусы: обработчик прерывания один. Поэтому, когда нет данных для передачи, но идет прием, обработчик прерывания вызванный приемником, ставит и событие готовности передатчика (бит в статусе USART TXRDY ведь установлен). При этом получается что будет установка уже установленного события. Есть ли тут криминал, не знаю. В доках по этому поводу ничего не нашел.
Рассматривал вариант организации передачи тоже через mailbox. Во-первых мне показалось это излишним усложнением. во-вторых, обработчик прерывания вызывается при освобождении передатчика. А если данные появились позже?
Ну и третий вариант, просто сделать задачу передачи с низшим приоритетом, и просто пулингом ждать освобождения передатчика, без прерываний. Другие задачи будут ее о необходимости прерывать. Уж совсем как-то некрасиво, да и задача передатчика не самая низшая по приоритетности.
В общем, интересно, кто какие подходы использует?
Не думаю что это имеет значение, но на всякий случай, контроллер AT91SAM7X...
|
|
|
|
|
Feb 28 2011, 06:37
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 11-02-09
Пользователь №: 44 714

|
вот как сделано у меня, прерывания для передачи не используются, только для приёма контроллер у меня lpc1343, но я думаю под ваш допилить можно переменные: Код static char recvbuf[256]; static char sendbuf[256]; static U8 txridx=0; static U8 txwidx=0; static U8 rxridx=0; static U8 rxwidx=0; OS_TID t_UARTTxTask; OS_TID t_UARTRdTask; __task void uartTXTask(void); и остальное Код void UART_SendData(char Data) { sendbuf[txwidx++]=Data; os_evt_set (OS_FLAG_UART_TXDATAPENDING, t_UARTTxTask); }
uint8_t UART_ReceiveData(void) { if (rxridx == rxwidx) { t_UARTRdTask = os_tsk_self (); os_evt_wait_or (OS_FLAG_UART_RECEIVED, 0xffff); os_evt_clr (OS_FLAG_UART_RECEIVED, t_UARTRdTask); } return (recvbuf[rxridx++]); }
uint8_t UART_DataAvailable(void) { uint8_t tmp = rxwidx - rxridx; return tmp<0?256-tmp:tmp; }
__task void uartTXTask (void) { while(1) { os_evt_wait_or(OS_FLAG_UART_TXDATAPENDING, 0xffff); while(txridx<txwidx) { LPC_UART->THR = sendbuf[txridx++] & UART_THR_MASKBIT; while (!(LPC_UART->LSR & UART_LSR_THRE)); } os_evt_clr(OS_FLAG_UART_TXDATAPENDING, t_UARTTxTask); } }
void __irq UART_IRQHandler(void) { uint8_t ch;
if (LPC_UART->IIR & UART_IIR_INTID_MASK == UART_IIR_INTID_RDA){ ch = (uint8_t)(LPC_UART->RBR & UART_RBR_MASKBIT); recvbuf[rxwidx++]=ch; isr_evt_set (OS_FLAG_UART_RECEIVED, t_UARTRdTask); } NVIC_ClearPendingIRQ(UART_IRQn); return; }
Сообщение отредактировал Vichkins - Feb 28 2011, 06:42
|
|
|
|
|
Mar 1 2011, 13:28
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-03-07
Пользователь №: 25 855

|
Цитата(Vichkins @ Feb 28 2011, 08:37)  вот как сделано у меня, прерывания для передачи не используются, только для приёма контроллер у меня lpc1343, но я думаю под ваш допилить можно и остальное Код uint8_t UART_ReceiveData(void) { if (rxridx == rxwidx) { t_UARTRdTask = os_tsk_self (); os_evt_wait_or (OS_FLAG_UART_RECEIVED, 0xffff); os_evt_clr (OS_FLAG_UART_RECEIVED, t_UARTRdTask); } return (recvbuf[rxridx++]); }
void __irq UART_IRQHandler(void) { uint8_t ch;
if (LPC_UART->IIR & UART_IIR_INTID_MASK == UART_IIR_INTID_RDA){ ch = (uint8_t)(LPC_UART->RBR & UART_RBR_MASKBIT); recvbuf[rxwidx++]=ch; isr_evt_set (OS_FLAG_UART_RECEIVED, t_UARTRdTask); } NVIC_ClearPendingIRQ(UART_IRQn); return; } Наверное так, с буфером даже лучше, по эффективности чем с mailbox'ами. Надо попробовать сравнить... А вот с передачей: Код LPC_UART->THR = sendbuf[txridx++] & UART_THR_MASKBIT; while (!(LPC_UART->LSR & UART_LSR_THRE)); собственно вот этого цикла while я и хотел избежать. Из-за малой скорости предачи это ожидание будет относительно долгое, а в это время могли бы выполняться некоторые менее приоритетные задачи...
|
|
|
|
|
Mar 1 2011, 21:16
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 11-02-09
Пользователь №: 44 714

|
ну тогда наверно лучше сигналить задаче передачи из прерывания, я пробовал так делать, но тк пока всё не в железе а в симуляторе keil, то передача в терминал производилась очень медленно и я сделал с циклом судя по вот этой табличке http://www.keil.com/support/man/docs/rlarm...timing_spec.htm, можно прикинуть что при использовании метода "сигналить задаче передачи из прерывания", при частоте 60МГц на ARM7 мы вряд ли сможем достич скоростей выше 100000 как вариант могу предложить сделать вариант с while и поставить достаточно быстрое переключение round-robin, если возможно можно ещё попробовать так, правда не знаю как будет работать Код LPC_UART->THR = sendbuf[txridx++] & UART_THR_MASKBIT; os_tsk_pass(); while (!(LPC_UART->LSR & UART_LSR_THRE)); теоретически так будет больше времени отдаватся остальным задачам
Сообщение отредактировал Vichkins - Mar 1 2011, 21:18
|
|
|
|
|
Mar 13 2011, 19:41
|
Группа: Новичок
Сообщений: 1
Регистрация: 28-05-09
Пользователь №: 49 695

|
Тоже приценивался к этой операционке. А что она работает только как раунд-робин? Мне показалось, что там есть возможность вытеснения.
|
|
|
|
|
Mar 15 2011, 18:08
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-03-07
Пользователь №: 25 855

|
Цитата(serbor @ Mar 13 2011, 21:41)  Тоже приценивался к этой операционке. А что она работает только как раунд-робин? Мне показалось, что там есть возможность вытеснения. нет, не только. Раунд-робин можно включать или нет в конфигурационном файле. Т.е на этапе компиляции можно выбрать пользоваться раунд-робин или обычной вытесняющей многозадачностью.
|
|
|
|
|
Mar 25 2011, 09:01
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-03-07
Пользователь №: 25 855

|
Цитата(sinc_func @ Mar 22 2011, 20:16)  - при отсутсвии каких-то "шевелений" в статусах этой задачи и необходимости чего-то "окучивать" - эта задача просто отдает активный статус через os_tsk_pass() другой задаче Цитата The os_tsk_pass function passes control to the next task of the same priority in the ready queue. If there is no task of the same priority in the ready queue, the current task continues and no task switching occurs. Нсколько я понял из описания, задаче с меньшим приоритетом os_tsk_pass управлени не отдаст. Кто-нить проверял как оно на практике? Round-robin не пользую.
|
|
|
|
|
Apr 8 2011, 13:19
|
Частый гость
 
Группа: Участник
Сообщений: 107
Регистрация: 29-05-10
Из: Пенза
Пользователь №: 57 619

|
Цитата(Shein @ Mar 25 2011, 13:01)  Нсколько я понял из описания, задаче с меньшим приоритетом os_tsk_pass управлени не отдаст. Кто-нить проверял как оно на практике? Round-robin не пользую. У себя в задачах я ориентируюсь пока только на Round-robin (не хочется напрягаться и тянуть без должной мотивации систему приоритетов)
|
|
|
|
|
Feb 25 2012, 00:10
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 11-02-09
Пользователь №: 44 714

|
uriy код был не из примеров переменная txwidx типа uint8_t и sendbuf[256], всё просто
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|