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

Стоит такая задача: необходимо в 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%) не там? Я что-то не учитываю в алгоритме? Или ошибочная реализация?

 

Спасибо за внимание :)

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


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

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

 

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

Модератор

Изменено пользователем IgorKossak

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


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

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

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


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

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

 

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

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

 

 

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

Я же писал - встроенный "калиброванный" RC генератор 9.6Мгц.

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

 

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

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


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

. В первом случае есть опасность, что в серийном производстве вылезет неточность калибровки безкварцевых процессоров, а переделать схематически уже будет нельзя. Я же писал - встроенный "калиброванный" RC генератор 9.6Мгц.

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

 

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

 

Я не много по другому делал СТАРТ. Ставил 0, запускал синхротаймер и разрешал прерывания от таймера, запрещал все другие и чистил все флаги от источников всех "лишних прерываний"

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


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

Я не много по другому делал СТАРТ. Ставил 0, запускал синхротаймер и разрешал прерывания от таймера, запрещал все другие и чистил все флаги от источников всех "лишних прерываний"

Предлагаете удлиннить "старт-бит"?

Но это же вроде будет не по стандарту.

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


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

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

post-26542-1201012185_thumb.jpg

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


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

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

 

 

 

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

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


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

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

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

Я как раз к этому варианту пока и склоняюсь.

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

 

 

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

Идея хороша, спасибо. А какие варинанты насчет декодирования (приема) Манчестера? Считать количество тактов после синхроимпульса? Или не делать высоких частот передачи, считать времена по таймеру? Но у приемника будут еще задачи (прием информации с "вольтметра" и передача сборных данных на комп, уже хардверным UART-ом), прерывания будут еще...

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


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

Текст фрагмента программы:

(фрагмент прерывания от переполнения таймера 0, передача очередного бита):

ldi accum, counter_preset ; 256-125

out timer0_data, accum ; загрузить регистр данных таймера 0

(...)

..................................................

Почему получается "середина" (от +/- 1%) не там?

..................................................

Спасибо за внимание :)

 

Доброго времени суток!

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 мкс.

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


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

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

 

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

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


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

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

 

Доброго времени суток!

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" - а пауза зачем?

 

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

 

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

 

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

 

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

Изменено пользователем sbw

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


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

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

 

Теоретически, для устойчивого приема непрерывного потока символов необходимо чтобы за 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.

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


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

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

 

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

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


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

По поводу того, зачем паузу ставить - defunct все гораздо более обстоятельно рассказал.

Я так понимаю, что автобод у Вас будет на принимающей стороне.

Тогда структура пакета данных предлагается такая:

0xAA, <data_size>,<data>,[crc8]

По первому байту синхронизация,

длина пакета включает в себя crc8,

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

Удачи!

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


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

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

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

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

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

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

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

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

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

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