Перейти к содержанию
    

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

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

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

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

 

запрос:

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

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

-посылка

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

 

ответ-

-число байт

-посылка

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

 

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

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

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

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

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

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

запрос:

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

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

-посылка

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

 

ответ-

-число байт

-посылка

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

 

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

 

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

 

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...