реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> software UART на tiny 13, может ли он быть надежным?
sbw
сообщение Jan 22 2008, 12:41
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 39
Регистрация: 5-10-07
Из: Харьков, Украина
Пользователь №: 31 107



Стоит такая задача: необходимо в tiny13 при программировании записать первую прошивку, считать данные, которые tiny 13 выдаст, после чего на основе этих данных подставить константы во вторую прошивку, которую уже записать "насовсем" и отправить прибор в путь. Иначе говоря, первая прошивка - калибровочная.
Подзадача: как получить данные из этой Tiny13 "на стенде"? Можно, конечно, писать их в EEPROM, потом считать программатором. Это "вообще". Но в конкретном случае данные - это то, что поступает с АЦП (а нужно откалибровать этот АЦП, то есть высчитать множитель для данных с АЦП, потому что делитель входного напряжения различается от изделия к изделию), напряжение, которое меряет АЦП - это нестабильное сетевое. То есть, нужен именно реал-таймовый поток данных с АЦП, идущий одновременно с потоком данных с калиброванного вольтметра, замеряющего это же сетевое напряжение, чтобы пересчитывать два числа (данные с АЦП калибруемого прибора и данные с вольтметра).
Как получить поток данных с tiny13?
Я предположил, что это можно сделать софтверным uart-ом (к тому же, свободных ног на этой тини - всего одна, на остальных что-то висит: делитель АЦП, реле, светодиоды). Вроде бы предположение "имело право на жизнь": ресурсов процессора для скорости 9600 хватает.
Но столкнулся с тем, что расчетные частоты чуть-чуть не попадают в диапазон требуемых. То есть, данные идут, но только если скорость отличается от расчетной процента на два.
Сначала я предположил, что дело в неточности заводской калибровки: по документации она имеет точность 10%, а требуется 1%. Сделал процедуру автокалибровки по импульсам 100 гц другого процессора. Но в итоге пришел к тому же самому: скорость передачи данных должна быть выше процента на два, чем рассчитывалось. Может быть, я где-то ошибся в алгоритме (ниже)? Или сам заложенный принцип неверен - нельзя полагаться на такую реализацию межпроцессорного обмена, когда нет принципиальной стабильности внутреннего RC-генератора? (и надо делать, скажем, синхронный обмен. Но мне тут уже принципиально интересно стало "в чем же проблема").
Текст фрагмента программы:

Константы и определения:
.equ counter_prescaler=2 ; clk/8
.equ counter_preset=256-125 ; 9 600 000/(8*125) = 9 600
.equ max_bit = 10 ; start + 8bit + stop
.def accum = r16 ; аккумулятор (регистр общего пользования)
.def accum2 = r17 ; второй аккумулятор
.def accum3 = r18 ; ...
.def xl = r26
.def xh = r27
.def yl = r28
.def yh = r29

(инициализация таймера в основной программе - включение прерывания по переполнению и установка делителя. Установка ноги Tx в "1")

(фрагмент прерывания от переполнения таймера 0, передача очередного бита):
ldi accum, counter_preset ; 256-125
out timer0_data, accum ; загрузить регистр данных таймера 0
(...)
; accum = байт для передачи
; accum3 = номер передаваемого бита

cpi accum3, 0 ; start-bit ? (0)
breq tx_send_start
cpi accum3, max_bit-1 ; stop-bit ? (9)
breq tx_send_stop

; если не старт-бит и не стоп-бит - передавать биты с 1 по 8
lsr accum ; сдвинуть весь передаваемый байт через Carry flag
brcc tx_send_0 ; бит в Cf = 0 ? если да- то переход на "поставить 0"
; если нет - то "поставить 1"

tx_send_stop: ; стоп-бит (1)
nop ; nop-ы - для выравнивания тактовых длительностей удержания разных битов.
tx_send_1:
nop
tx_set_1 ; поставить 1 на ножке порта Tx (MOSI)
rjmp tx_send_continue

tx_send_start: ; поставить старт-бит (0)
nop
nop
nop
nop
tx_send_0:
tx_set_0 ; поставить 1 на ножке порта Tx (MOSI)

tx_send_continue: ; дальше - уже не принципиальные моменты, пересчет и сохранение переменных

inc accum3 ; увеличить номер бита для передачи
cpi accum3, max_bit ; сколько осталось бит для передачи (0..9)
breq tx_next ; если 10 -то поменять указатели и укоротить очередь

st X, accum ; сохранить сдвинутый байт ==>>
rjmp tx_bit_pointer_store ; выход с сохранением нового количества бит

tx_next:
clr accum3 ; подготовить передачу следующего байта (0й)
ldd accum2, Y+1 ; загрузить указатель байта
inc accum2 ; подвинуть указатель байта на следующую позицию
ld accum, Y ; загрузить длину очереди
dec accum ; уменьшить длину на 1
st Y, accum ; и сохранить длину
tst accum ; проверить: длина очереди =0?
brne tx_continue
clr accum2 ; если да - то обнулить указатель байта
tx_continue:
std Y+1, accum2 ; сохранить указатель

tx_bit_pointer_store:
std Y+2, accum3 ; сохранить номер передаваемого бита

Вот в таком виде оно все работает.
НО!
если задать counter_preset=256-125-1 - то уже нет.
А если counter_preset=256-125+5 - то еще да. Почему получается "середина" (от +/- 1%) не там? Я что-то не учитываю в алгоритме? Или ошибочная реализация?

Спасибо за внимание smile.gif
Go to the top of the page
 
+Quote Post
VladimirYU
сообщение Jan 22 2008, 13:14
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782



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

Удалил ненужное цитирование, больше ТАК не делайте.
Модератор


Сообщение отредактировал IgorKossak - Jan 22 2008, 17:36
Go to the top of the page
 
+Quote Post
GDI
сообщение Jan 22 2008, 13:34
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



Скорость передачи любого уарта определяется частотой задающего генератора, сколько она у вас? Может не мучиться а программатором все же снять инфу?


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
sbw
сообщение Jan 22 2008, 13:44
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 39
Регистрация: 5-10-07
Из: Харьков, Украина
Пользователь №: 31 107



Цитата(VladimirYU @ Jan 22 2008, 15:14) *
Сложно что то сказать, так как непонятно какие еще процессы выполняются, особенно есть ли еще прерывания. Если они есть то это может быть причиной потери синхронизации. Побовал подобное делать на меге16, потребовался второй UART по 1 линии причем, передачу удалось сделать надежной на 9600, но прерывания все кроме синхротаймера запрещал на момент посылок. А вот с приемом натрахался всласть, пришлось все длительности как и Вам в ручную подгонять. Но Вам вроде прием не нужен?


Нет, других прерываний нет. После этой процедуры в этом же прерывании идет процедура добавления в очередь передачи еще 7 байт, но она вызывается два раза в секунду. Скорости процессора хватает, пробовал перейти на 4800 - результат тот же.
Не могу определиться: или "додалбывать" этот алгоритм, вручную подбирая коэффициенты, или переходить на синхронную передачу. В первом случае есть опасность, что в серийном производстве вылезет неточность калибровки безкварцевых процессоров, а переделать схематически уже будет нельзя. Во втором случае - надо все сейчас делать заново, в том числе электрическую схему менять,чтобы перейти на тот же синхронный алгоритм (добавить хотя-бы один провод стробирования)


Цитата(GDI @ Jan 22 2008, 15:34) *
Скорость передачи любого уарта определяется частотой задающего генератора, сколько она у вас? Может не мучиться а программатором все же снять инфу?

Я же писал - встроенный "калиброванный" RC генератор 9.6Мгц.
Делится на 8, после этого счетчик отсчитывает (256-125) отсчетов для прерывания, в котором передается очередной бит.

Может мне увеличить промежуток между передачей байт?..
Go to the top of the page
 
+Quote Post
VladimirYU
сообщение Jan 22 2008, 14:01
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782



Цитата(sbw @ Jan 22 2008, 16:44) *
. В первом случае есть опасность, что в серийном производстве вылезет неточность калибровки безкварцевых процессоров, а переделать схематически уже будет нельзя. Я же писал - встроенный "калиброванный" RC генератор 9.6Мгц.
Делится на 8, после этого счетчик отсчитывает (256-125) отсчетов для прерывания, в котором передается очередной бит.

Может мне увеличить промежуток между передачей байт?..


Я не много по другому делал СТАРТ. Ставил 0, запускал синхротаймер и разрешал прерывания от таймера, запрещал все другие и чистил все флаги от источников всех "лишних прерываний"
Go to the top of the page
 
+Quote Post
sbw
сообщение Jan 22 2008, 14:21
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 39
Регистрация: 5-10-07
Из: Харьков, Украина
Пользователь №: 31 107



Цитата(VladimirYU @ Jan 22 2008, 16:01) *
Я не много по другому делал СТАРТ. Ставил 0, запускал синхротаймер и разрешал прерывания от таймера, запрещал все другие и чистил все флаги от источников всех "лишних прерываний"

Предлагаете удлиннить "старт-бит"?
Но это же вроде будет не по стандарту.
Go to the top of the page
 
+Quote Post
Ruslan_Shaida
сообщение Jan 22 2008, 14:37
Сообщение #7


Участник
*

Группа: Новичок
Сообщений: 19
Регистрация: 27-03-07
Из: Кривой Рог
Пользователь №: 26 542



Как вариант, можно использовать код типа «Манчестер» («manchester»). При этом методе передача каждого бита данных синхронизируется импульсом, а значение бита (0 или 1) определяется промежутком времени до следующего импульса (см. рис). При его использовании, требование к стабильности тактовой частоты гораздо меньше, чем в классическом коде. И как раз используется только одна нога.
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
prottoss
сообщение Jan 22 2008, 15:05
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Может проще софтверного UART соорудить софтверный SPI а на стенде предусмотреть место для "большого брата" на "нормальном" AVR который будет слэйвом для калибруемого МК, и будет от него гнать данные по "настоящему" UART куда надо smile.gif



Понадобится так же всего две ноги - для эмуляции MOSI и SCK


--------------------
Go to the top of the page
 
+Quote Post
sbw
сообщение Jan 22 2008, 15:17
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 39
Регистрация: 5-10-07
Из: Харьков, Украина
Пользователь №: 31 107



Цитата(prottoss @ Jan 22 2008, 17:05) *
Может проще софтверного UART соорудить софтверный SPI а на стенде предусмотреть место для "большого брата" на "нормальном" AVR который будет слэйвом для калибруемого МК, и будет от него гнать данные по "настоящему" UART куда надо smile.gif
Понадобится так же всего две ноги - для эмуляции MOSI и SCK

Я как раз к этому варианту пока и склоняюсь.
Но хочется определенности с исходной задачей: решаема она или нет? Мало ли, может в будущем прийдется с ней столкнуться, а не будет времени/ресурсов для резерва и разбирательств.


Цитата(Ruslan_Shaida @ Jan 22 2008, 16:37) *
Как вариант, можно использовать код типа «Манчестер» («manchester»). При этом методе передача каждого бита данных синхронизируется импульсом, а значение бита (0 или 1) определяется промежутком времени до следующего импульса (см. рис). При его использовании, требование к стабильности тактовой частоты гораздо меньше, чем в классическом коде. И как раз используется только одна нога.

Идея хороша, спасибо. А какие варинанты насчет декодирования (приема) Манчестера? Считать количество тактов после синхроимпульса? Или не делать высоких частот передачи, считать времена по таймеру? Но у приемника будут еще задачи (прием информации с "вольтметра" и передача сборных данных на комп, уже хардверным UART-ом), прерывания будут еще...
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 22 2008, 16:03
Сообщение #10


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(sbw @ Jan 22 2008, 15:41) *
Текст фрагмента программы:
(фрагмент прерывания от переполнения таймера 0, передача очередного бита):
ldi accum, counter_preset ; 256-125
out timer0_data, accum ; загрузить регистр данных таймера 0
(...)
..................................................
Почему получается "середина" (от +/- 1%) не там?
..................................................
Спасибо за внимание smile.gif


Доброго времени суток!
1. Кусок кода, ИМХО, должен выглядеть так:
Код
.equ counter_preset_imho=125      ;

   in     accum, tcnt0                          ; или по-Вашему timer0_data
   subi  accum,counter_preset_imho    ; учли то, что таймер тоже живет своей жизнью
   out    tcnt0,accum                          ; и может увеличиться на 1, а то и аж на 2


2. У Вас ошибка набегает на целых 10 битах. Поэтому и середина неизвестно где.
3. После стоп-бита добавьте длиннющщую паузу в 100 мкс.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jan 22 2008, 16:17
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



На кварце 73728 я реализовывал так называемый autobod. Работал суперстабильно на частоте передачи 115200. Таким образом запаса скорости для софтверной реадизации UARTа на частоте 9600/4800 должно быть достаточно. Тем не менее нормированная частота UART 2%. Поэтому не важно какая у вас частота, но стабильность её должна быть не ниже этой цифры. То есть вам придётся подбирать частоту. Либо калибровать её каким-то образом. Можно и работать "в ответ на принимаемые данные". По этим данным и осуществлять калибровку.

По моему у t13 есть модуль USI. У Atmel имеется апликэйшн по использованию USI в режиме UART.
Go to the top of the page
 
+Quote Post
sbw
сообщение Jan 23 2008, 00:06
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 39
Регистрация: 5-10-07
Из: Харьков, Украина
Пользователь №: 31 107



Точно! В этом и была суть! Огромное спасибо! smile.gif

Цитата(_Pasha @ Jan 22 2008, 18:03) *
Доброго времени суток!
1. Кусок кода, ИМХО, должен выглядеть так:
Код
.equ counter_preset_imho=125    ;

   in     accum, tcnt0                        ; или по-Вашему timer0_data
   subi  accum,counter_preset_imho; учли то, что таймер тоже живет своей жизнью
   out    tcnt0,accum                        ; и может увеличиться на 1, а то и аж на 2


2. У Вас ошибка набегает на целых 10 битах. Поэтому и середина неизвестно где.
3. После стоп-бита добавьте длиннющщую паузу в 100 мкс.


У меня стоит делитель тактовой на 8, а начало процедуры прерывания выглядит так:
(сама таблица прерываний - переход)
Код
        rjmp  t0overflow; 6 - Timer0 overflow

(обработчик прерывания) :
Код
t0overflow:
        push  accum
        in    accum, status_reg
        push  accum
        wdr
        out   timer0_data, counter_preset_reg


Считаю такты:
rjmp - 2 такта,
push - 2 такта,
in - такт,
push - 2 такта,
wdr - такт.
Итого на момент загрузки таймера получается 8 тактов, плюс собственно загрузка (out) - такт, плюс вход в прерывание - 4 такта, плюс выход из sleep (idle) - еще 4 такта!
Действительно, как раз и набегает на 17 тактов на момент окончания загрузки регистра, то есть в этот момент таймер уже насчитал 2.
Теперь понятна разница...

по поводу "3" - а пауза зачем?

Цитата(SasaVitebsk @ Jan 22 2008, 18:17) *
На кварце 73728 я реализовывал так называемый autobod. Работал суперстабильно на частоте передачи 115200. Таким образом запаса скорости для софтверной реадизации UARTа на частоте 9600/4800 должно быть достаточно. Тем не менее нормированная частота UART 2%. Поэтому не важно какая у вас частота, но стабильность её должна быть не ниже этой цифры. То есть вам придётся подбирать частоту. Либо калибровать её каким-то образом. Можно и работать "в ответ на принимаемые данные". По этим данным и осуществлять калибровку.

По моему у t13 есть модуль USI. У Atmel имеется апликэйшн по использованию USI в режиме UART.


А можете рассказать в двух словах, как реализовывался этот "автобод"? Это на прием, в смысле? По какому признаку определялась скорость передачи?

У Tiny13 нет вообще никаких интерфейсов передачи данных, насколько я помню. Из периферии только таймер, АЦП и компаратор, ну еще debug wire, он не в счет.

Сообщение отредактировал sbw - Jan 23 2008, 00:11
Go to the top of the page
 
+Quote Post
defunct
сообщение Jan 23 2008, 00:10
Сообщение #13


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата
Но столкнулся с тем, что расчетные частоты чуть-чуть не попадают в диапазон требуемых. То есть, данные идут, но только если скорость отличается от расчетной процента на два.


Теоретически, для устойчивого приема непрерывного потока символов необходимо чтобы за 9 бит кадра от СТАРТа до последнего бита данных ошибка между передатчиком и приемником не составила более 50% интервала одного бита данных. Но даже если эта ошибка будет в диапазоне от 50% до 100% - шанс правильно принять один кадр все равно есть, а раз можно правильно принять один кадр, то можно принять и поток -- для этого достаточно растягивать СТОП бит (например посылать 2-3-4-5 СТОП битов), что полностью компенсирует накопленную ошибку предыдущего символа.

Цитата
У меня стоит делитель тактовой на 8, а начало процедуры прерывания выглядит так:

Зачем ее делить?! Оставляйте 9.6Mhz.
Причины 2:
1. При калибровке будет более быстрая реакция на прерывания, что должно прибавить стабильности.
2. В конечном приборе снизится энергопотребление при условии использования SLEEP. Т.к. МК будет быстрее обрабатывать события и засыпать. Кривая тока от частоты растет в два раза медленнее чем кривая производительности от частоты.

Цитата
Вот в таком виде оно все работает.
НО!
если задать counter_preset=256-125-1 - то уже нет.

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

PS: Здесь http://electronix.ru/forum/index.php?showt...10934&st=30 можете посмотреть пример программного UART'a, работал вроде стабильно и на прием и на передачу 9600/19200/38400.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Jan 23 2008, 06:16
Сообщение #14


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Действительно, как раз и набегает на 17 тактов на момент окончания загрузки регистра, то есть в этот момент таймер уже насчитал 2.Теперь понятна разница...


Сергей, именно это я тебе в асе и рассказывал wink.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 23 2008, 08:41
Сообщение #15


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



По поводу того, зачем паузу ставить - defunct все гораздо более обстоятельно рассказал.
Я так понимаю, что автобод у Вас будет на принимающей стороне.
Тогда структура пакета данных предлагается такая:
0xAA, <data_size>,<data>,[crc8]
По первому байту синхронизация,
длина пакета включает в себя crc8,
ессно, длина пакета не должна быть сильно большой. Вместо crc не применяйте контрольную сумму - проверено - фуфло полное.
Удачи!
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 17th July 2025 - 21:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01494 секунд с 7
ELECTRONIX ©2004-2016