Jump to content

    
Sign in to follow this  
inventor

Протокол внутрь драйвера или поверх драйвера?

Recommended Posts

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

Устройство опрашивает 4 АЦП и кроме того должно писать данные на SD карту и делать еще кое-какие расчеты и обмениваться по UART и Ethernet.

В других устройствах мы использовали вот примерно такой протокол обмена RS485 -он очень хорошо работал-

 

запрос:

-первый байт адрес устроства

-второй команда и число след. байт в посылке

-посылка

-контрольная сумма CRC16

 

ответ-

-число байт

-посылка

-контрольная сумма CRC16

 

так как сейчас я решил это устройство делать с помошью этой небольшой оськи и у меня вот такой вопрос возник-все примеры этой оси предлагают уже написанный драйвер UART в котором все общение может вестись на уровне write / read.

Но мне это как бы совсем не нужно, все другие камни , которые я программировал, что там весь обмен идет на прерываниях по чтения и по записи,

и, соответственно ошибочные пакеты, неправильная контрольная сумма, не мой адрес и пр. -я просто отбрасываю и не вожусь с ними.

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

Вобщем эта ось мне нужна, чтобы распределить обмен между запущенными процессами (ака задачи)-например

та же запись на карту.

и мне вот интересно спросить у знатоков, если писать обмен для этой OS так как делаю я-это правильно с точки зрения этой оси,

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

И еще, мне это интересно, так как и для обработки прерываний от АЦП нужно будет то же решить, как все это по-правильному сделать.

 

Share this post


Link to post
Share on other sites

Драйвер из примеров - он пример и есть, использовать его никто не заставляет.

 

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

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

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

Share this post


Link to post
Share on other sites
запрос:

-первый байт адрес устроства

-второй команда и число след. байт в посылке

-посылка

-контрольная сумма CRC16

 

ответ-

-число байт

-посылка

-контрольная сумма CRC16

 

Но мне это как бы совсем не нужно, все другие камни , которые я программировал, что там весь обмен идет на прерываниях по чтения и по записи,

и, соответственно ошибочные пакеты, неправильная контрольная сумма, не мой адрес и пр. -я просто отбрасываю и не вожусь с ними.

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

Я не знаток ОС, но штуки с разной длинной посылок лучше отдать драйверу. Может сделать двухуровневый, но по прерываниям. То есть взять Ваш протокол и поместить в драйвер.

Share this post


Link to post
Share on other sites
Драйвер из примеров - он пример и есть, использовать его никто не заставляет.

 

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

 

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

 

почему плохо?

ДМА можно напрямую использовать если наперед знаешь сколько придет.

как по вашему сделать лучше?

Share this post


Link to post
Share on other sites
почему плохо?

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

А подобные ограничения удобства работы не добавляют.

 

ДМА можно напрямую использовать если наперед знаешь сколько придет.

как по вашему сделать лучше?

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

Share this post


Link to post
Share on other sites
Потому что у атмеловских UART'ов нет FIFO. Если, например, битовая скорость интерфейса равна 115200, то в системе нельзя блокировать прерывание UART дольше чем на 87мкс.

А подобные ограничения удобства работы не добавляют.

 

 

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

 

не совсем понял, поясните?

 

Share this post


Link to post
Share on other sites
не совсем понял, поясните?

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

 

Думаю, проще будет привести фрагмент обработчика:

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, но периферия у них практически идентичная.

Share this post


Link to post
Share on other sites
Я так понимаю, нужно пояснить вторую часть.

 

Думаю, проще будет привести фрагмент обработчика:

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 первых байта с адресом длиной.

потом выключаю прерывание и включаю дма с уже настроенным размером пересылки.

если я бы делал как в вашем примере я опять таки принят бы то, что мне не нужно.

например я начал принимать с середины посылки, не с моим адресом, а мне эти данные не нужны.

Share this post


Link to post
Share on other sites
например я начал принимать с середины посылки, не с моим адресом, а мне эти данные не нужны.

А если байт в середине посылки случайно совпадет с адресом, и DMA встанет колом в результате?

Share this post


Link to post
Share on other sites
А если байт в середине посылки случайно совпадет с адресом, и DMA встанет колом в результате?

 

если не принимает за определенное время-то прерывание дма отрубаются

и прием uart начинается заново.

случая который вы описали ни разу не случался.

при тестировании мы опробываем разные ложные посылки.

 

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