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

Исходники UART with PDC для Atmel ARM

и причем здесь прием?

Не помню что там выключается. Я рассматривал исходя из передачи, поэтому так написал. Имел ввиду весь UART. Ведь если при передаче выключается передатчик, то при преме должен выключаться приемник. Ведь так? К тому же передача из произвольных буферов я еще представляю, а прием в произвольные - это как? Вызвали GetData, передав указатель, вернулись, что-то делаем, потом каким-то образом узнаем что данные получены. Ну, буфер заполнен. Новые данные принимать некуда. Надо подставлять новый. А в этот момент бабац, и пресловутое запрещение прерываний. А мы ведь в пользовательском коде, ваще самые некотируемые.

Нее. Так не правильно.

Если в системе крутится один драйвер UART, то невозможно. Но обычно крутится еще много чего другого безо всяких катастроф.

Обработчик прерываний не должен выполнять никакой длительной работы работы внутри себя. Это даже по Windows (далеко не реал-тайм) - закон! Если же в программе допускаются такие задержки, то ни при каком способе работы с UART нельзя гарантировать, что не произойдет потери принятого байта. Ведь задержка может произойти между переключениями буферов в пользовательском коде (а такое переключение более длительное, чем метод, используемый у меня).

 

 

Если Вы не против, подкину еще одну тему для обсуждения. Есть такое замечательное устройство GSM-модем SIM508. Так вот он при приеме пакета данных сообщает об этом следующим образом "+IPD<размер>:". Есть идея обработки обычных сообщений через обычные прерывания. Т.е. посимвольно. Ибо неизвестно, когда же закончится входящее сообщение. А парсить его на предмет <CR><LF> расточительно. Зато принимать пакеты заранее известной длинны оч. удобно через PDC. Есть вопрос: теоретически возможна ли потеря символов при переключении режимов работы. Что-то я в документации ничего толкового не нашел по этому вопросу...

Переключаться между режимами может быть и можно, но не правильно. Думаю, в данном случае надо всегда работать через PDC. После "+IPD<размер>:" есть таймаут или сразу данные идут? В любом случае, настраиваем таймаут (ну там, возможны другие команды, URC), указываем буфер, ждем когда он заполнится (полностью или нет, не важно). По любому парсим начиная с начала. Если нашли "+IPD<размер>:", остальную часть буфера рассматриваем как данные. Три варианта: 1) после данных есть еще строковые ответы, 2) данные кончаются в конце буфера, 3) не все данные влезли в буфер. Во третьем случае указываем еще буфер, но после заполнения помним, что там данные вначале. А потом могут быть строки.

Алгоритм не тривиален. Если его делать влоб - не получиться. Но могу псевдокодом расписать, как делать.

 

Кстати, что насчет URC? У некоторых телефонов возможны такие фишки:

AT+CMGL=0 (запрос списка новых входящих SMS)

+CMGL: 1,0,,24 (ответ: индекс, статус,,длина)

0791xxxxxxxxxxF1040B919720380422F6 (это PDU - закодированная SMS)

+CMTI: "ME",39 (хопа, пришло URC - уведомление - о новом сообщении)

00006001701041130005C8329BFD06 (продолжение PDU)

Как такое обрабатывать?

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


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

Если Вы не против, подкину еще одну тему для обсуждения. Есть такое замечательное устройство GSM-модем SIM508. Так вот он при приеме пакета данных сообщает об этом следующим образом "+IPD<размер>:". Есть идея обработки обычных сообщений через обычные прерывания. Т.е. посимвольно. Ибо неизвестно, когда же закончится входящее сообщение. А парсить его на предмет <CR><LF> расточительно. Зато принимать пакеты заранее известной длинны оч. удобно через PDC. Есть вопрос: теоретически возможна ли потеря символов при переключении режимов работы. Что-то я в документации ничего толкового не нашел по этому вопросу...

В свое время я извращался подобным образом на AT91x40xxx. У них PDC был без двойной буферизации, так что приходилось останавливать прием до окончания буфера и быстренько подключать следующий.

ИМХО, можно, но лучше так не делать. Парсить <CR><LF> будет значительно проще.

 

Ведь если при передаче выключается передатчик, то при преме должен выключаться приемник. Ведь так?

Почему это?

 

К тому же передача из произвольных буферов я еще представляю, а прием в произвольные - это как?

Что Вы понимаете под термином "произвольный буфер"?

 

Обработчик прерываний не должен выполнять никакой длительной работы работы внутри себя. Это даже по Windows (далеко не реал-тайм) - закон! Если же в программе допускаются такие задержки, то ни при каком способе работы с UART нельзя гарантировать, что не произойдет потери принятого байта. Ведь задержка может произойти между переключениями буферов в пользовательском коде (а такое переключение более длительное, чем метод, используемый у меня).

Да кто же спорит? Просто в одном случае допустима задержка в 2 символа, а во втором - в 1 буфер PDC, размер которого можно регулировать. А ОС, пользовательский код и прочее к делу не относится.

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


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

ИМХО, можно, но лучше так не делать. Парсить <CR><LF> будет значительно проще.

Т.е. делать по моему? Я вспомнил! Сделал побайтно из-за того, что так проще принимать строки.

Почему это?

Что Вы понимаете под термином "произвольный буфер"?

Совсем забыл как работает этот PDU. Сейчас глянул. Без отключения приемника не обойтись, так как установить адрес на следующий буфер и счетчик надо одновременно! Это если адрес буфера будет все время разный, "произвольный", для обработчика прерываний, неизвестный ему заранее. Если использовать один и тот же буфер или пару, то без выключения приемника обойтись можно.

Плюс с PDC появляется проблема с приемом строк произвольной длины. Как ее организовать? Ловить прерывание по таймауту, копировать (!) буфер от значения до текущего адреса? Или PDC переходит на следующий буфер по таймауту?

Опишите пожалуйста парой слов Ваш алгоритм, так сказать путь данных от UART до пользовательского буфера. Куда указывает адрес и следующий адрес в PDC (в течение всего цикла)?

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


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

2 Andrey Sudnov. Да уж алгоритм не тривиален. Пауз никаких нет. Иногда модем пакеты выплевывает за раз, иногда бьет на куски и каждый обрамляет <CR><LF>..<CR><LF>. Это еще больше затрудняет разгребание "влоб". Сейчас использую Ваш фифо с некоторыми добавлениями, типа подсчета принятых строк и т.д. Никак не могу понять - на больших обьемах где-то выпадает символ. Overrun я победил, остались свои косяки.

 

2 aaarrr, убедили. :) Завтра волю в кулак и буду переписывать. Тут только что осознал, что можно запоминать позицию до котрой в прошлый раз парсил и в след раз начинать с нее. Осталось посчитать, как часто надо проверять буфер на наличие новых строк.

 

З.Ы. ненавижу "равноправные" интерфейсы. Другое дело SPI, пока не спросили слэйв молчит. :)

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


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

Т.е. делать по моему? Я вспомнил! Сделал побайтно из-за того, что так проще принимать строки.

Нет, делать побайтно я не советовал.

 

Совсем забыл как работает этот PDU. Сейчас глянул. Без отключения приемника не обойтись, так как установить адрес на следующий буфер и счетчик надо одновременно! Это если адрес буфера будет все время разный, "произвольный", для обработчика прерываний, неизвестный ему заранее. Если использовать один и тот же буфер или пару, то без выключения приемника обойтись можно.

Объясните мне, какой смысл писать адрес и счетчик в разное время?

 

Понял Ваше определение "произвольного" буфера. ИМХО, те буферы, с которыми работает PDC должны быть однозначно фиксированными - задача PDC и буферизации состоит прежде всего в разгрузке процессора и обеспечении надежного приема, а дальнейшая судьба данных - дело пользовательского приложения, и обработчик прерывания заботиться о ней не должен.

 

Плюс с PDC появляется проблема с приемом строк произвольной длины. Как ее организовать? Ловить прерывание по таймауту, копировать (!) буфер от значения до текущего адреса? Или PDC переходит на следующий буфер по таймауту?

Опишите пожалуйста парой слов Ваш алгоритм, так сказать путь данных от UART до пользовательского буфера. Куда указывает адрес и следующий адрес в PDC (в течение всего цикла)?

Попробую, парой слов не обойдется, правда. :)

Итак:

1. Заводим два одинаковых буфера.

2. Прописываем в PDC_RPR и PDC_RCR адрес и длину первого буфера, в PDC_RNPR и PDC_RNCR - второго.

3. При поступлении прерывания ENDRX копируем данные из буфера PDC в пользовательский (у меня это обычно FIFO, если принимается поток, или набор фиксированных буферов, если обмен идет в пакетном режиме). Адрес и длину освободившегося буфера записываем в PDC_RNPR и PDC_RNCR.

Наличие места в FIFO или свободного буфера на этом этапе - целиком проблема пользовательского приложения.

4. По TIMEOUT все несколько сложнее:

4.1 Запрещаем - увы - прерывания

4.2 Выключаем PDC

4.3 Запоминаем PDC_RCR

4.4 Если PDC_RNCR != 0, то ставим PDC_RPR = PDC_RNPR, PDC_RCR = PDC_RNCR, PDC_RNCR = 0,

в противном случае игнорируем п.4.6

4.5 Включаем PDC и прерывания

4.6 Копируем данные и прописываем PDC_RNPR и PDC_RNCR аналогично п.3

Время запрета PDC и прерываний получается очень малым.

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


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

Итак:

1. Заводим два одинаковых буфера.

2. Прописываем в PDC_RPR и PDC_RCR адрес и длину первого буфера, в PDC_RNPR и PDC_RNCR - второго.

3. При поступлении прерывания ENDRX копируем данные из буфера PDC в пользовательский (у меня это обычно FIFO, если принимается поток, или набор фиксированных буферов, если обмен идет в пакетном режиме). Адрес и длину освободившегося буфера записываем в PDC_RNPR и PDC_RNCR.

Наличие места в FIFO или свободного буфера на этом этапе - целиком проблема пользовательского приложения.

4. По TIMEOUT все несколько сложнее:

4.1 Запрещаем - увы - прерывания

4.2 Выключаем PDC

4.3 Запоминаем PDC_RCR

4.4 Если PDC_RNCR != 0, то ставим PDC_RPR = PDC_RNPR, PDC_RCR = PDC_RNCR, PDC_RNCR = 0,

в противном случае игнорируем п.4.6

4.5 Включаем PDC и прерывания

4.6 Копируем данные и прописываем PDC_RNPR и PDC_RNCR аналогично п.3

Время запрета PDC и прерываний получается очень малым.

В пункте 3 копируем внутри обработчика прерываний?

Мне кажетсе, при приеме необходимости выключать PDC нет (точно PDC? А не UART? А если была задержка перед обработкой прерывания по TIMEOUT и в тот момент, когда выключили PDC как раз поступил новый байт, ну а раз PDC выключен - запомнили и выдали новый запрос на прерывание, но уже без PDC?). Почему необходимо начинать прием в следующий буфер вместо хвоста текущего?

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

При приеме момент смены указателя и значения только один - в прерывании ENDRX, когда вероятность того, что произойдет переключение буферов в PDC очень мала (не успеет просто так много данных поступить).

 

 

2 Andrey Sudnov. Да уж алгоритм не тривиален. Пауз никаких нет. Иногда модем пакеты выплевывает за раз, иногда бьет на куски и каждый обрамляет <CR><LF>..<CR><LF>. Это еще больше затрудняет разгребание "влоб". Сейчас использую Ваш фифо с некоторыми добавлениями, типа подсчета принятых строк и т.д. Никак не могу понять - на больших обьемах где-то выпадает символ. Overrun я победил, остались свои косяки.

Символ пропадает в передатчике или приемнике? Вы так спокойно об этом говорите! Ни в коем случае ничего не должно пропадать! Если есть ошибка у меня, а это возможно, о ней надо сообщить, чтобы исправиить ну или отказаться от моего исходника - не исключаю и такой вариант.

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


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

а что за беда от выключения PDC? ну выключили, переставили буферы, снова включили - перенос данных продолжился с того же места.

у меня PDC обычно включен в обе стороны, активны прерывания AT91C_US_RXBUFF | AT91C_US_TXBUFE | AT91C_US_TIMEOUT. Копирования массивов нет, кольцевые буферы заполняются/разгребаются непосредственно функциями putchar/getchar, которые, впрочем, тоже приостанавливают PDC на десяток-другой машинных команд, проблем от этого не испытывал.

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


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

а что за беда от выключения PDC? ну выключили, переставили буферы, снова включили - перенос данных продолжился с того же места.

у меня PDC обычно включен в обе стороны, активны прерывания AT91C_US_RXBUFF | AT91C_US_TXBUFE | AT91C_US_TIMEOUT. Копирования массивов нет, кольцевые буферы заполняются/разгребаются непосредственно функциями putchar/getchar, которые, впрочем, тоже приостанавливают PDC на десяток-другой машинных команд, проблем от этого не испытывал.

Допустим PDC выключен. В этот момент приходит новый символ. Устанавливается RXRDY, но так как он замаскирован - прерывания не происходит. Закончили работу с буферами, включили PDC. Скорее всего Вы правы - символ, который уже принят, уйдет в буфер. Это было бы логично. Надо конечно проверить для верности.

Я признаю, что мой драйвер чрезмерно усложнен из-за того что не выключает PDC. В этом нет смысла, поэтому лучше его использовать только в качестве обучающего (ну там все-таки есть некоторые трюки).

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


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

Взрыв из прошлого;)

 

Кому интересен subj, у мну есть что добавить.

Первое. Это актуально на новом железе Atmel(поменялся ли интерфейс UART и PDC)?

Второе. Появились ли какие новые реализации работы через PDC хорошие?(та, что была в linux kernel времен 2.6 - мне не нравится)

Третье. Теоретически возможно написать поблочный, а не посимвольный алгоритм для приемника, который будет работать в паре с предложенным алгоритмом передатчика БЕЗ ОТКЛЮЧЕНИЯ КОНТРОЛЛЕРОВ UART/PDC(читайте первый и седьмой пост, а также последние несколько).

Этот алгоритм сложнее, чем алгоритм для передатчика(а он сам не прост, по сравнению с linux версией).

И он возможен, так как настройку PDC МОЖНО начинать с установки второй пары указатель-счетчик(которая Next)! Аппаратно значения переносятся сразу в первую пару(текущую) и сразу же начинается прием в этот буфер. Т.е. возможна такая настройка буферов: 1) проверяем свободен ли Next 2) Настраиваем Next 3) переходим к 1. Какбэ не очевидный момент, но выявленный экспериментально на AT91SAM7S64.

В SDK от Atmel же происходит сначала проверка и заполнение первой пары, и только если она не свободна - заполнение пары Next. ЭТО ДЕЛАЕТ НЕВОЗМОЖНЫМ АТОМАРНУЮ УСТАНОВКУ ОБОИХ ПАР И ПРИХОДИТСЯ ОТКЛЮЧАТЬ КОНТРОЛЛЕР.

Да, перенос происходит в момент установки регистра счетчика.

Публиковать пока не буду, но кому интересно, готовый исходник пришлю, так как надо тестить.

 

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


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

Можно вообще не передергивать контроллер и работать без прерываний.

Достаточно даже одного буфера.

Если next освободился кидаем в него адрес и размер. После заполнения счет начинается сначала. Получается кольцевой буфер.

Остается только сверять текущий указатель и забирать принятое.

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


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

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

Зачем нужны два буфера?

Они позволяют на HIGHLOAD обрабатывать входящие данные прямо в тех же буферах, которые заполнялись PDC, БЕЗ КОПИРОВАНИЯ!

Насколько все это нужно, каждый решает в меру своей испорченности;)

Можно сделать как-то эдак хитроватисто, но надо проверять. А зн велком.

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


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

"Правда в том, что никакой ложки нет."

а) не надо теребить текущий буфер, только читать состояние регистров.

и) проверять и обновлять содержимое только next буфера.

q) чтобы еще и работать с данными нужен +1 буфер.

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


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

"Правда в том, что никакой ложки нет."

Ложки нет, ложкодержатели есть;)

Выкладывай что ли свой вариант, а то не очень понятно, что значит "теребить".

Ну или в subj укажи, что можно упростить по твоему. Только когда он делался, я еще не знал про next.

В версию алгоритма с приемником около 100 строк добавляется

 

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


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

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

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

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

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

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

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

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

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

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