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

Програмный 1-wire на прерываниях таймера

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

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


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

При отсутствии аппаратного 1wire принято использовать uart https://www.maximintegrated.com/en/app-note...ndex.mvp/id/214

Кем принято?

Открываем указанную ссылку, читаем:

Для сброса и обнаружения устройства нужно послать код 0xF0 на скорости 9600. И:

1) "если устройства нет, то на RX получим 0xF0"; Утверждение не вызывает сомнения.

2) "если устройство есть, то на RX получим что-то отличное от 0xF0"; А вот тут уже - фиг вам!

Открываем описание интерфейса 1-wire, читаем:

Чтобы сформировать сигнал «Reset», — «Мастер» должен притянуть уровень на шине к нулю на время не менее 480 мкс и не более 960 мкс (480 мкс ≤ TRSTL < 960 мкс). После этого он должен отпустить шину и, не менее, чем на 480 мкс, прекратить свою активность на шине (TRSTH > 480 мкс). «Слэйвы», не ранее, чем через 15 мкс, но и не позднее, чем через 60 мкс после того, как «Мастер» отпустит шину (15 мкс < TPDH < 60 мкс), должны сформировать на шине низкий уровень (это и есть сигнал присутствия), длительностью от 60 до 240 мкс (60 мкс < TPDL < 240 мкс), после чего они также отпускают шину.

Оп-ля - приехали! :05:

При скорости 9600 длительность бита == 104мкс. Предположим что частоты генераторов мастера и слэйва идеально совпадают. Тогда, после завершения передачи мастером младших 4-х бит кода 0xF0, на шине наступит фронт сигнала. И в это время UART мастера начнёт приём 4-го бита. Точка сэмплирования этого бита находится на расстоянии 104/2=52мкс от указанного фронта (конца RESET). Но ведь из описания выше следует, что слэйв имеет право начать формировать сигнал присутствия через 60мкс после завершения RESET. Т.е. - уже после того как мастер считает с шины состояние 4-го бита! И мастер получит в 4-м бите лог.1. :smile3009:

Окей, ладно - может хоть в следующем бите мастер сможет узреть на шине несчастного слэйва?? :fman:

Но опять же - из описания выше можно узнать, что сигнал присутствия генерируемый слэйвом, может быть длительностью всего 60мкс. Но ведь мы помним, что между точками сэмплирования RX-битов мастером расстояния == 104 мкс (1 бит UART). Получается, что если импульс присутствия начнётся через 60 мкс после конца RESET и продлится всего 60 мкс, то он аккурат проскочит между двумя точками сэмплирования UART.RX мастера. И мастер его просто не заметит!

Хотя мальчик-то есть, но вот колхоз на UART его не видит.... :crying:

А значит такую реализацию уже нельзя считать 1-wire. Ну никак нельзя.

И это мы ещё даже не учли влияния разности частот генераторов мастера и слэйва, а также влияние ёмкости линии. А также не учли, что делитель UART-а может быть дробным (а длина бита UART - переменной). Там будет ещё веселее.

После этого дальше читать указанную ссылку смысла уже нет.

 

Да этому "стандарту" уже почти 30 лет, обсосан до костей.

Тайминги такие, что заведется с полпинка на любом античном МК даже на встроенном RC-генераторе.

Да ладно?

Не будем углубляться в приём/передачу, но раз "обсосан", то объясните как с помощью UART хотя-бы обнаружить такой слэйв-девайс, который в полном соответствии с мануалом, формирует импульс присутствия с началом через 15...60 мкс после завершения RESET, и длительностью 60...240 мкс?

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

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


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

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

 

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


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

для этого есть аппаратные таймеры
Т.е. используются и таймеры и УАРТ?

В чём смысл?

 

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


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

Когда-то я выкладывал сюда код, работающий на STM32 и на MSP430.

Вот, смотрите, может подойдёт для Вас. http://electronix.ru/forum/index.php?showt...p;#entry1089884

 

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


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

1-Wire вполне себе реализовывался на SPI 32bit. Правда, делал его на древнем уже LPC2103

Главное - пин MOSI правильно настроить, чтобы только вниз тянул, push-pull отключить, если возможно, или сгородить на двух транзисторах

post-20514-1538046155_thumb.png

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


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

1-Wire вполне себе реализовывался на SPI 32bit. Правда, делал его на древнем уже LPC2103

Главное - пин MOSI правильно настроить, чтобы только вниз тянул, push-pull отключить, если возможно, или сгородить на двух транзисторах

post-20514-1538046155_thumb.png

Лучше вот такая схема:

w6xvp_uzkvxpwkmo3vscfwp1zyk.png

По I2C работает идеально. ;)

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


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

Лучше вот такая схема:

По I2C работает идеально. ;)

Не, ну кто бы спорил :)

Вопрос в том, что у меня без всяких +200р к стоимости девайса... Хотя, если ценник ему ковырнадцать тысяч, то и DS2484 вполне себе уместна :biggrin:

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


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

Красивый выход из прерывания с переключением контекста

Вам нужно посмотреть на примеры реализации механизма callback.

Вкратце, реализовываете функцию для настройки таймера в one shot режиме и в прерывании таймера (через n us) вызываете необходимый вам callback

static void (*_cb)(void) = NULL;

void TIMERn_Handler(void) {
   // TODO: Clear timer status or stop if neccesary
   if( _cb ) {
       _cb();
   }
}

void setup_timer(uint32_t delay_us, void *callback ) {
   _cb = callback ;
   //TODO: configure hardware timer
}

Далее, набрасываем функции которые будут вызываться последовательно:

static void _save_t1(void);
static void _reset(void);

void start(void) {
   Switch_Out();
   setup_timer(480, _reset);
}

static void _reset(void) {
   Switch_In();
   setup_timer(80, _save_t1);
}

static void _save_t1(void) {
   Ack[0]=T1;
   //TODO ...
  if(Ack[0] == 1) {
       setup_timer(80, _something1);
   } else {
       setup_timer(10, _something2);
   }
}

Думаю суть ясна, для начала транзакиции нужно вызвать start(), а дальше все пойдет по реализованной вами цепочке.

Если таких "прижков" выйдет много, локаничней релизовать таблицы для "линейных участков":

static struct {
    uinr32_t delay_us;
    void *next_cb;
}_chain_init[] = {
    {.delay_ms = 480, .next_cb = _reset},
    {.delay_ms = 80, .next_cb = _save_t1},
};

Пользовать это можно так:

    index++;
    setup_timer(_chain_init[index].delay_ms , _chain_init[index].next_cb);

 

Ну и понятно функция setup_timer, должны бать быстрой, что бы не поплыли микросекундные тайминги.

Код писал без проверки компиляции, так что извиняйте за описки.

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


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

Решение на uart 1wire Отлично работает даже с usb-uart преобразователем CP2102. CP2102 работает без кварца и скорее всего подстраивает частоту по SOF кадрам, думаю там разброс больше чем 20 ppm.

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


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

Решение на uart 1wire Отлично работает даже с usb-uart преобразователем CP2102.
Кроме пустословия, по делу, есть что сказать?

Ещё раз читаем: Почему UART - не 1-wire

 

CP2102 скорее всего подстраивает частоту по SOF кадрам.
Бред.

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


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

Не знаю, зачем выделять на это целый UART... Я сделал на таймере в режиме сравнения. Благодаря этому можно использовать любую ножку свободную на МК. Обработчик таймера:

#define T1 4
#define T2 7
#define T3 51
#define T4 59
#define T5 89
#define T6 409
#define T7 499

// TypeOperation - тип запрашиваемой операции:
//   ONE_WIRE_INIT - формирование импульса сброса;
//   ONE_WIRE_GET_TIME_SLOT - формирование тайм-слота чтения;
//   ONE_WIRE_SET_TIME_SLOT_0 - формирование тайм-слота записи лог. 0;
//   ONE_WIRE_SET_TIME_SLOT_0 - формирование тайм-слота записи лог. 1.
//
// ResultOperation - результат чтения тайм-слота (только при чтении).
//
// StatusOperation - флаг завершенности работы автомата.
//
// Перед использованием автомата необходимо указать тип операции и включить
// таймер TIMER_START(). Затем дождаться завершения работы автомата.
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
	static unsigned char FSMState = 0;

	switch(TypeOperation)
	{
	  // автомат формирования импульса сброса
		case ONE_WIRE_INIT:
		{
			switch(FSMState)
			{
				case 0: TIM2->ARR = T7; RESET_LINE(WIRE);                  break;
				case 1: TIM2->ARR = T5; SET_LINE(WIRE);                    break;
				case 2: TIM2->ARR = T6; ResultOperation = GET_LINE(WIRE);  break;
				case 3: TIMER_STOP(); TIM2->ARR = T1; StatusOperation = 1; break;
			}
			FSMState = (FSMState + 1) & 0x3; break;
		}

		// автомат формирования тайм-слота чтения
		case ONE_WIRE_GET_TIME_SLOT:
		{
			switch(FSMState)
			{
				case 0: TIM2->ARR = T1; RESET_LINE(WIRE);                  break;
				case 1: TIM2->ARR = T2; SET_LINE(WIRE);                    break;
				case 2: TIM2->ARR = T3; ResultOperation = GET_LINE(WIRE);  break;
				case 3: TIMER_STOP(); TIM2->ARR = T1; StatusOperation = 1; break;
			}
			FSMState = (FSMState + 1) & 0x3; break;
		}

		// автомат формирования тайм-слота записи
		case ONE_WIRE_SET_TIME_SLOT_0: case ONE_WIRE_SET_TIME_SLOT_1:
		{
			switch(FSMState)
			{
				case 0: TIM2->ARR = (TypeOperation == HW_ONE_WIRE_SET_TIME_SLOT_0) ? T4 : T1; RESET_LINE(GPIO_ONE_WIRE); break;
				case 1: TIM2->ARR = (TypeOperation == HW_ONE_WIRE_SET_TIME_SLOT_0) ? T1 : T4; SET_LINE(GPIO_ONE_WIRE);   break;
				case 2: TIMER_STOP(); TIM2->ARR = T1; ++FSMState; StatusOperation = 1;                                   break;
			}
			FSMState = (FSMState + 1) & 0x3; break;
		}
	}

	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
}

 

Кстати, попутно тут хочу узнать, как красиво организовать счётчик, который считает до, например, 5 и сбрасывается в 0 без условия if(). Ну то есть вычитая, сдвигая... Интересно можно ли так сделать. Для ровных битовых чисел, как в коде выше, как видно, я битовой маской обнуляю. А вот интересно, как быть с числами, не являющихся степенями 2.

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


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

Не знаю, зачем выделять на это целый UART... Я сделал на таймере в режиме сравнения.

Вы наверное перепутали: наверное всё-таки в режиме захвата (capture), а не сравнения (compare). :rolleyes:

Да, это стандартное решение. Вообще не понимаю здешних товарищей, которые пытаются колхозить на чём угодно, только не делать как надо. :cranky:

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


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

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

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

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

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

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

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

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

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

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