Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Протокол внутрь драйвера или поверх драйвера?
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
inventor
Сейчас разрабатываем устройтство на AVR32-я пишу внутреннюю прогу для него, вот такой вопрос, даже не знаю, в какой раздел мне его писать.
Устройство опрашивает 4 АЦП и кроме того должно писать данные на SD карту и делать еще кое-какие расчеты и обмениваться по UART и Ethernet.
В других устройствах мы использовали вот примерно такой протокол обмена RS485 -он очень хорошо работал-

запрос:
-первый байт адрес устроства
-второй команда и число след. байт в посылке
-посылка
-контрольная сумма CRC16

ответ-
-число байт
-посылка
-контрольная сумма CRC16

так как сейчас я решил это устройство делать с помошью этой небольшой оськи и у меня вот такой вопрос возник-все примеры этой оси предлагают уже написанный драйвер UART в котором все общение может вестись на уровне write / read.
Но мне это как бы совсем не нужно, все другие камни , которые я программировал, что там весь обмен идет на прерываниях по чтения и по записи,
и, соответственно ошибочные пакеты, неправильная контрольная сумма, не мой адрес и пр. -я просто отбрасываю и не вожусь с ними.
так как длина посылок разная-сначала идет прием IRQ UART , а после получения длинны посылки включаю ДМА чтобы принять все остальное.
Вобщем эта ось мне нужна, чтобы распределить обмен между запущенными процессами (ака задачи)-например
та же запись на карту.
и мне вот интересно спросить у знатоков, если писать обмен для этой OS так как делаю я-это правильно с точки зрения этой оси,
или все таки нужно писать драйвер, а потом в верхнем уровне протокола делать разбор всей этой байды-типа парсинга того что я принял.
И еще, мне это интересно, так как и для обработки прерываний от АЦП нужно будет то же решить, как все это по-правильному сделать.
aaarrr
Драйвер из примеров - он пример и есть, использовать его никто не заставляет.

Только вот это -
Цитата(inventor @ Dec 29 2011, 21:26) *
так как длина посылок разная-сначала идет прием IRQ UART , а после получения длинны посылки включаю ДМА чтобы принять все остальное.

просто ужас как плохо, ибо требует низкой латентности прерываний UART.
Tiro
Цитата(inventor @ Dec 29 2011, 20:26) *
запрос:
-первый байт адрес устроства
-второй команда и число след. байт в посылке
-посылка
-контрольная сумма CRC16

ответ-
-число байт
-посылка
-контрольная сумма CRC16

Но мне это как бы совсем не нужно, все другие камни , которые я программировал, что там весь обмен идет на прерываниях по чтения и по записи,
и, соответственно ошибочные пакеты, неправильная контрольная сумма, не мой адрес и пр. -я просто отбрасываю и не вожусь с ними.
так как длина посылок разная-сначала идет прием IRQ UART , а после получения длинны посылки включаю ДМА чтобы принять все остальное.

Я не знаток ОС, но штуки с разной длинной посылок лучше отдать драйверу. Может сделать двухуровневый, но по прерываниям. То есть взять Ваш протокол и поместить в драйвер.
inventor
Цитата(aaarrr @ Dec 29 2011, 20:44) *
Драйвер из примеров - он пример и есть, использовать его никто не заставляет.

Только вот это -

просто ужас как плохо, ибо требует низкой латентности прерываний UART.


почему плохо?
ДМА можно напрямую использовать если наперед знаешь сколько придет.
как по вашему сделать лучше?
aaarrr
Цитата(inventor @ Dec 29 2011, 22:24) *
почему плохо?

Потому что у атмеловских UART'ов нет FIFO. Если, например, битовая скорость интерфейса равна 115200, то в системе нельзя блокировать прерывание UART дольше чем на 87мкс.
А подобные ограничения удобства работы не добавляют.

Цитата(inventor @ Dec 29 2011, 22:24) *
ДМА можно напрямую использовать если наперед знаешь сколько придет.
как по вашему сделать лучше?

DMA можно использовать всегда, просто нужно использовать его совместно с прерыванием по тайм-ауту приемника UART.
inventor
Цитата(aaarrr @ Dec 29 2011, 21:37) *
Потому что у атмеловских UART'ов нет FIFO. Если, например, битовая скорость интерфейса равна 115200, то в системе нельзя блокировать прерывание UART дольше чем на 87мкс.
А подобные ограничения удобства работы не добавляют.


DMA можно использовать всегда, просто нужно использовать его совместно с прерыванием по тайм-ауту приемника UART.


не совсем понял, поясните?
aaarrr
Цитата(inventor @ Dec 29 2011, 23:42) *
не совсем понял, поясните?

Я так понимаю, нужно пояснить вторую часть.

Думаю, проще будет привести фрагмент обработчика:
Код
u_char us0_rx_buff[2][UART0_RX_BUFFER_SIZE];
u_char us0_rx_bidx;
u_int us0_rx_read;

void uart0_ini(void)
{
    us0_rx_read = 0;
    us0_rx_bidx = 0;
    us0_tx_bidx = 0;

    ...
    *AT91C_US0_RTOR = 10;    // One 8-N-1 char time

    ...
    *AT91C_US0_RPR = (u_int)&us0_rx_buff[0][0];
    *AT91C_US0_RCR = UART0_RX_BUFFER_SIZE;
    *AT91C_US0_RNPR = (u_int)&us0_rx_buff[1][0];
    *AT91C_US0_RNCR = UART0_RX_BUFFER_SIZE;
    *AT91C_US0_PTCR = AT91C_PDC_RXTEN;

    *AT91C_US0_IER = AT91C_US_TIMEOUT | AT91C_US_ENDRX;
}

//**************************************
//*    

void uart0_handle_timout(void)
{
    u_char *buff = &us0_rx_buff[us0_rx_bidx][0];
    u_int a;

    a = UART0_RX_BUFFER_SIZE - *AT91C_US0_RCR;
    *AT91C_US0_CR = AT91C_US_STTTO;
    fifo_write(&uart0_rx_fifo, a - us0_rx_read, &buff[us0_rx_read]);
    us0_rx_read = a;
}

//**************************************
//*    

void uart0_handle_endrx(void)
{
    u_char *buff = &us0_rx_buff[us0_rx_bidx][0];

    *AT91C_US0_RNPR = (u_int)buff;
    *AT91C_US0_RNCR = UART0_RX_BUFFER_SIZE;

    fifo_write(&uart0_rx_fifo, UART0_RX_BUFFER_SIZE - us0_rx_read, &buff[us0_rx_read]);
    us0_rx_read = 0;
    us0_rx_bidx ^= 1;
}

fifo_write - процедура записи данных в программное FIFO, на входе указатель на FIFO, количество записываемых байт, указатель на источник данных.
Вместо этого вызова можно отправить полученные данные приложению любым удобным способом.

Данные будут передаваться приложению по мере заполнения буферов, либо же, если поток остановился, по аппаратному тайм-ауту UART'а. Прерывания можно свободно запрещать на время заполнения RX_BUFFER_SIZE.

P.S. Да, пример от семейства AT91, но периферия у них практически идентичная.
inventor
Цитата(aaarrr @ Dec 29 2011, 22:56) *
Я так понимаю, нужно пояснить вторую часть.

Думаю, проще будет привести фрагмент обработчика:
Код
u_char us0_rx_buff[2][UART0_RX_BUFFER_SIZE];
u_char us0_rx_bidx;
u_int us0_rx_read;

void uart0_ini(void)
{
    us0_rx_read = 0;
    us0_rx_bidx = 0;
    us0_tx_bidx = 0;

    ...
    *AT91C_US0_RTOR = 10;    // One 8-N-1 char time

    ...
    *AT91C_US0_RPR = (u_int)&us0_rx_buff[0][0];
    *AT91C_US0_RCR = UART0_RX_BUFFER_SIZE;
    *AT91C_US0_RNPR = (u_int)&us0_rx_buff[1][0];
    *AT91C_US0_RNCR = UART0_RX_BUFFER_SIZE;
    *AT91C_US0_PTCR = AT91C_PDC_RXTEN;

    *AT91C_US0_IER = AT91C_US_TIMEOUT | AT91C_US_ENDRX;
}

//**************************************
//*    

void uart0_handle_timout(void)
{
    u_char *buff = &us0_rx_buff[us0_rx_bidx][0];
    u_int a;

    a = UART0_RX_BUFFER_SIZE - *AT91C_US0_RCR;
    *AT91C_US0_CR = AT91C_US_STTTO;
    fifo_write(&uart0_rx_fifo, a - us0_rx_read, &buff[us0_rx_read]);
    us0_rx_read = a;
}

//**************************************
//*    

void uart0_handle_endrx(void)
{
    u_char *buff = &us0_rx_buff[us0_rx_bidx][0];

    *AT91C_US0_RNPR = (u_int)buff;
    *AT91C_US0_RNCR = UART0_RX_BUFFER_SIZE;

    fifo_write(&uart0_rx_fifo, UART0_RX_BUFFER_SIZE - us0_rx_read, &buff[us0_rx_read]);
    us0_rx_read = 0;
    us0_rx_bidx ^= 1;
}

fifo_write - процедура записи данных в программное FIFO, на входе указатель на FIFO, количество записываемых байт, указатель на источник данных.
Вместо этого вызова можно отправить полученные данные приложению любым удобным способом.

Данные будут передаваться приложению по мере заполнения буферов, либо же, если поток остановился, по аппаратному тайм-ауту UART'а. Прерывания можно свободно запрещать на время заполнения RX_BUFFER_SIZE.

P.S. Да, пример от семейства AT91, но периферия у них практически идентичная.



при разной длине я принимаю по уарту только 2 первых байта с адресом длиной.
потом выключаю прерывание и включаю дма с уже настроенным размером пересылки.
если я бы делал как в вашем примере я опять таки принят бы то, что мне не нужно.
например я начал принимать с середины посылки, не с моим адресом, а мне эти данные не нужны.
aaarrr
Цитата(inventor @ Dec 30 2011, 00:28) *
например я начал принимать с середины посылки, не с моим адресом, а мне эти данные не нужны.

А если байт в середине посылки случайно совпадет с адресом, и DMA встанет колом в результате?
inventor
Цитата(aaarrr @ Dec 29 2011, 23:39) *
А если байт в середине посылки случайно совпадет с адресом, и DMA встанет колом в результате?


если не принимает за определенное время-то прерывание дма отрубаются
и прием uart начинается заново.
случая который вы описали ни разу не случался.
при тестировании мы опробываем разные ложные посылки.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.