|
|
|
Програмный 1-wire на прерываниях таймера, Красивый выход из прерывания с переключением контекста |
|
|
|
Sep 26 2018, 22:07
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(uriy @ Sep 26 2018, 21:45) Кем принято? Открываем указанную ссылку, читаем: Для сброса и обнаружения устройства нужно послать код 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 мкс), после чего они также отпускают шину.Оп-ля - приехали! При скорости 9600 длительность бита == 104мкс. Предположим что частоты генераторов мастера и слэйва идеально совпадают. Тогда, после завершения передачи мастером младших 4-х бит кода 0xF0, на шине наступит фронт сигнала. И в это время UART мастера начнёт приём 4-го бита. Точка сэмплирования этого бита находится на расстоянии 104/2=52мкс от указанного фронта (конца RESET). Но ведь из описания выше следует, что слэйв имеет право начать формировать сигнал присутствия через 60мкс после завершения RESET. Т.е. - уже после того как мастер считает с шины состояние 4-го бита! И мастер получит в 4-м бите лог.1. Окей, ладно - может хоть в следующем бите мастер сможет узреть на шине несчастного слэйва?? Но опять же - из описания выше можно узнать, что сигнал присутствия генерируемый слэйвом, может быть длительностью всего 60мкс. Но ведь мы помним, что между точками сэмплирования RX-битов мастером расстояния == 104 мкс (1 бит UART). Получается, что если импульс присутствия начнётся через 60 мкс после конца RESET и продлится всего 60 мкс, то он аккурат проскочит между двумя точками сэмплирования UART.RX мастера. И мастер его просто не заметит! Хотя мальчик-то есть, но вот колхоз на UART его не видит.... А значит такую реализацию уже нельзя считать 1-wire. Ну никак нельзя. И это мы ещё даже не учли влияния разности частот генераторов мастера и слэйва, а также влияние ёмкости линии. А также не учли, что делитель UART-а может быть дробным (а длина бита UART - переменной). Там будет ещё веселее. После этого дальше читать указанную ссылку смысла уже нет. Цитата(Forger @ Sep 26 2018, 22:48) Да этому "стандарту" уже почти 30 лет, обсосан до костей. Тайминги такие, что заведется с полпинка на любом античном МК даже на встроенном RC-генераторе. Да ладно? Не будем углубляться в приём/передачу, но раз "обсосан", то объясните как с помощью UART хотя-бы обнаружить такой слэйв-девайс, который в полном соответствии с мануалом, формирует импульс присутствия с началом через 15...60 мкс после завершения RESET, и длительностью 60...240 мкс? Это ведь как ловить рыбку сетью, у которой размер ячеи больше размера самой рыбки - конечно есть вероятность что поймаешь, но можно и с голоду опухнуть
|
|
|
|
|
Sep 27 2018, 05:23
|
Местный
Группа: Участник
Сообщений: 211
Регистрация: 18-03-13
Из: Питер
Пользователь №: 76 081
|
Цитата(Forger @ Sep 27 2018, 10:04) для этого есть аппаратные таймеры Т.е. используются и таймеры и УАРТ? В чём смысл?
|
|
|
|
|
Sep 27 2018, 05:30
|
Профессионал
Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831
|
Цитата(Smen @ Sep 27 2018, 08:23) Т.е. используются и таймеры и УАРТ? Цитирую: Цитата(Smen) Я не использую для этого UART
--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
|
|
|
|
|
Sep 27 2018, 12:29
|
Частый гость
Группа: Свой
Сообщений: 167
Регистрация: 25-12-09
Из: Минск
Пользователь №: 54 460
|
Цитата Красивый выход из прерывания с переключением контекста Вам нужно посмотреть на примеры реализации механизма callback. Вкратце, реализовываете функцию для настройки таймера в one shot режиме и в прерывании таймера (через n us) вызываете необходимый вам callback CODE 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 } Далее, набрасываем функции которые будут вызываться последовательно: CODE 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, должны бать быстрой, что бы не поплыли микросекундные тайминги. Код писал без проверки компиляции, так что извиняйте за описки.
|
|
|
|
|
Sep 28 2018, 05:24
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(uriy @ Sep 28 2018, 07:54) Решение на uart 1wire Отлично работает даже с usb-uart преобразователем CP2102. Кроме пустословия, по делу, есть что сказать? Ещё раз читаем: Почему UART - не 1-wireЦитата(uriy @ Sep 28 2018, 07:54) CP2102 скорее всего подстраивает частоту по SOF кадрам. Бред.
|
|
|
|
|
Sep 28 2018, 11:15
|
Местный
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264
|
Не знаю, зачем выделять на это целый UART... Я сделал на таймере в режиме сравнения. Благодаря этому можно использовать любую ножку свободную на МК. Обработчик таймера: CODE #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.
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|