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

 
 
> Проблема с функцией задержки., STM32F107
Jenya7
сообщение Jun 27 2016, 09:05
Сообщение #1


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

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Какая то ну очень странная проблема.
Я сделал функцию задержки так.
Код
void Delay_us(uint32_t us)
{
    uint32_t ticks = 72 * us;
    SysTick->LOAD = ticks;
    SysTick->CTRL |= 0x01;  //enable
    while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk));
    SysTick->CTRL &= ~0x01; //disable
}

Проверяю
Код
PIN_OUT_PP(One_Wire_Pin);
while (1)
{
    PIN_ON(One_Wire_Pin);
    Delay_us(500);
    PIN_OFF(One_Wire_Pin);
    Delay_us(500);
}

Вижу хороший сигнал 500 микросек. Никаких проблем.
А вот в этой функции
Код
unsigned int One_Wire_Reset(GPIO_TypeDef * GPIOx, uint16_t PINx)
{
    unsigned int tmp;
    PIN_IN(GPIOx, PINx);
    if ((PIN_SYG(GPIOx, PINx))==0)    return One_Wire_Bus_Low_Error;

    PIN_OUT_PP(GPIOx, PINx);
    PIN_OFF(GPIOx, PINx);
    Delay_us(480);
    PIN_ON(GPIOx, PINx);
    PIN_IN(GPIOx, PINx);
    Delay_us(60);

    if ((PIN_SYG(GPIOx, PINx))==0) tmp=One_Wire_Success;
        else tmp=One_Wire_Error_No_Echo;
    Delay_us(Time_After_Reset);
    return tmp;
}

я вижу сигнал идет вниз на 350 микро (вместо 480). Кручу и так и этак, ума не приложу в чем проблема

Сообщение отредактировал Jenya7 - Jun 27 2016, 09:06
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Tarbal
сообщение Jun 29 2016, 18:13
Сообщение #2


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

Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(Jenya7 @ Jun 27 2016, 13:05) *
Какая то ну очень странная проблема.
Я сделал функцию задержки так.
Код
void Delay_us(uint32_t us)
{
    uint32_t ticks = 72 * us;
    SysTick->LOAD = ticks;
    SysTick->CTRL |= 0x01;  //enable
    while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk));
    SysTick->CTRL &= ~0x01; //disable
}


Я болезненно отношусь к выжиганию времени в функции задержки.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 30 2016, 08:05
Сообщение #3


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

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Цитата(Tarbal @ Jun 29 2016, 23:13) *
Я болезненно отношусь к выжиганию времени в функции задержки.

Я думал над тем как это сделать без задержек. Единственное решение к которому я пришел - прерывания таймера и State Machine в прерывании. Но так как система довольно громоздкая и там куча всяких прерываний не хочу к этой куче добавлять еще маленькую тележку.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 30 2016, 08:48
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Jenya7 @ Jun 30 2016, 11:05) *
Единственное решение к которому я пришел - прерывания таймера и State Machine в прерывании.
Я делал на одном прерывани таймера, использовал три модуля захвата/сравнения (Capture/Compare) и событие переполнения (UIF) таймера. Конечного автомата нет, точнее он выродился в проверку флагов CCxIF в обработчике прерывания. Получилось довольно компактно.
При обмене битом первый модуль сравнения настраиваю на tLOW1, второй на tRDW, третий на tLOW0, ARR на tSLOT.
Для сброса первый модуль настраиваю на tRSTL, второй на tRSTL+tPDLOW, третий на tRSTL+tRSTH, ARR на tRSTL+tRSTH.
Перед запуском прерываний задаю передаваемые биты (прием = передача всех единиц) и количество битов. В прерывании уменьшаю счетчик и по достижении сигналю флаг окончания обмена.
С эти же обработчиком удалось сделать и поиск устройств (там обмен идет двухбитовыми посылками).
Прерывание пришлось сделать высокоприоритетным, поскольку время tRDW-tLOW1 достаточно мало.

CODE

// Pin_out, Pin_in - ссылки на бит линии в bitband-области. Если процессор не поддерживает bitband, то можно вставить команды управления портом.
uint8_t one_wire::exchange(uint8_t in, uint_fast8_t bits)
{ // биты передаются начиная с младшего, принимаются в старший.
Shifter = in;
Bit_counter = bits;
{
TCritSect cs;
Pin_out = 0;
Timer->CR1 = 0
| 0 * (TIM_CR1_CKD & -TIM_CR1_CKD) // Dead-time clock, 0 = timer clock
| 0 * TIM_CR1_ARPE // ARR buffering
| 0 * (TIM_CR1_CMS & -TIM_CR1_CMS) // 0 = edge-aligned, 1...3 = center-aligned mode 1...3
| 0 * TIM_CR1_DIR // Direction, 0 = up, 1 = down
| 0 * TIM_CR1_OPM // One pulse mode, 1 = stop counter at update event
| 0 * TIM_CR1_URS // Update request source, 0 = any, 1 = only counter under-/overflow
| 0 * TIM_CR1_UDIS // Update event generation disabling
| 1 * TIM_CR1_CEN // Counter enable
;
}
Done_flag.wait();
return Shifter;
}

void one_wire::handler()
{
uint_fast16_t Status = Timer->SR;
Timer->SR = ~Status;

if(Status & TIM_SR_CC1IF) // bit output time
{
if(Shifter & (1 << 0))
Pin_out = 1;
Shifter >>= 1;
}

if(Status & TIM_SR_CC2IF) // bus sample time
{
if(Pin_in)
Shifter |= (1 << 7);
}

if(Status & TIM_SR_CC3IF) // bus release time
Pin_out = 1;

if(Status & TIM_SR_UIF) // end of slot
{
if(!--Bit_counter)
{
Timer->CR1 = 0; // stop timer
Timer->CNT = 0;
OS::TISRW ISR_wrapper;
Done_flag.signal_isr();
}
else
Pin_out = 0; // start new slot
}
}

bool one_wire::reset()
{
Mutex.lock();

Timer->ARR = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // slot time: 480 uS + 480 uS
Timer->CCR1 = T3_CLK / 2 * uint64_t(480) / (1000 * 1000); // bus release: 480 uS
Timer->CCR2 = T3_CLK / 2 * uint64_t(480 + 60) / (1000 * 1000); // bus sample: 480 + 60 uS
Timer->CCR3 = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // dummy

if(exchange((1 << 0), 1) & (1 <<7))
{
Mutex.unlock();
return false;
}

Timer->ARR = T3_CLK / 2 * uint64_t(15 + 45 + 45) / (1000 * 1000); // slot time: 15 + 45 + 45 uS
Timer->CCR1 = T3_CLK / 2 * uint64_t(9) / (1000 * 1000); // bit write: 9 uS
Timer->CCR2 = T3_CLK / 2 * uint64_t(18) / (1000 * 1000); // bus sample: 18 uS
Timer->CCR3 = T3_CLK / 2 * uint64_t(60) / (1000 * 1000); // bus release: 60 uS

return true;
}

uint8_t one_wire::receive()
{
return exchange(0xFF, 8);
}

bool one_wire::transmit(uint8_t data)
{
return exchange(data, 8) == data;
}
Сейчас посмотрел на этот код - можно было использовать one-pulse mode. Надо будет переделать.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 30 2016, 09:30
Сообщение #5


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

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Цитата(Сергей Борщ @ Jun 30 2016, 13:48) *
Я делал на одном прерывани таймера, использовал три модуля захвата/сравнения (Capture/Compare) и событие переполнения (UIF) таймера. Конечного автомата нет, точнее он выродился в проверку флагов CCxIF в обработчике прерывания. Получилось довольно компактно.
При обмене битом первый модуль сравнения настраиваю на tLOW1, второй на tRDW, третий на tLOW0, ARR на tSLOT.
Для сброса первый модуль настраиваю на tRSTL, второй на tRSTL+tPDLOW, третий на tRSTL+tRSTH, ARR на tRSTL+tRSTH.
Перед запуском прерываний задаю передаваемые биты (прием = передача всех единиц) и количество битов. В прерывании уменьшаю счетчик и по достижении сигналю флаг окончания обмена.
С эти же обработчиком удалось сделать и поиск устройств (там обмен идет двухбитовыми посылками).
Прерывание пришлось сделать высокоприоритетным, поскольку время tRDW-tLOW1 достаточно мало.

CODE

// Pin_out, Pin_in - ссылки на бит линии в bitband-области. Если процессор не поддерживает bitband, то можно вставить команды управления портом.
uint8_t one_wire::exchange(uint8_t in, uint_fast8_t bits)
{ // биты передаются начиная с младшего, принимаются в старший.
Shifter = in;
Bit_counter = bits;
{
TCritSect cs;
Pin_out = 0;
Timer->CR1 = 0
| 0 * (TIM_CR1_CKD & -TIM_CR1_CKD) // Dead-time clock, 0 = timer clock
| 0 * TIM_CR1_ARPE // ARR buffering
| 0 * (TIM_CR1_CMS & -TIM_CR1_CMS) // 0 = edge-aligned, 1...3 = center-aligned mode 1...3
| 0 * TIM_CR1_DIR // Direction, 0 = up, 1 = down
| 0 * TIM_CR1_OPM // One pulse mode, 1 = stop counter at update event
| 0 * TIM_CR1_URS // Update request source, 0 = any, 1 = only counter under-/overflow
| 0 * TIM_CR1_UDIS // Update event generation disabling
| 1 * TIM_CR1_CEN // Counter enable
;
}
Done_flag.wait();
return Shifter;
}

void one_wire::handler()
{
uint_fast16_t Status = Timer->SR;
Timer->SR = ~Status;

if(Status & TIM_SR_CC1IF) // bit output time
{
if(Shifter & (1 << 0))
Pin_out = 1;
Shifter >>= 1;
}

if(Status & TIM_SR_CC2IF) // bus sample time
{
if(Pin_in)
Shifter |= (1 << 7);
}

if(Status & TIM_SR_CC3IF) // bus release time
Pin_out = 1;

if(Status & TIM_SR_UIF) // end of slot
{
if(!--Bit_counter)
{
Timer->CR1 = 0; // stop timer
Timer->CNT = 0;
OS::TISRW ISR_wrapper;
Done_flag.signal_isr();
}
else
Pin_out = 0; // start new slot
}
}

bool one_wire::reset()
{
Mutex.lock();

Timer->ARR = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // slot time: 480 uS + 480 uS
Timer->CCR1 = T3_CLK / 2 * uint64_t(480) / (1000 * 1000); // bus release: 480 uS
Timer->CCR2 = T3_CLK / 2 * uint64_t(480 + 60) / (1000 * 1000); // bus sample: 480 + 60 uS
Timer->CCR3 = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // dummy

if(exchange((1 << 0), 1) & (1 <<7))
{
Mutex.unlock();
return false;
}

Timer->ARR = T3_CLK / 2 * uint64_t(15 + 45 + 45) / (1000 * 1000); // slot time: 15 + 45 + 45 uS
Timer->CCR1 = T3_CLK / 2 * uint64_t(9) / (1000 * 1000); // bit write: 9 uS
Timer->CCR2 = T3_CLK / 2 * uint64_t(18) / (1000 * 1000); // bus sample: 18 uS
Timer->CCR3 = T3_CLK / 2 * uint64_t(60) / (1000 * 1000); // bus release: 60 uS

return true;
}

uint8_t one_wire::receive()
{
return exchange(0xFF, 8);
}

bool one_wire::transmit(uint8_t data)
{
return exchange(data, 8) == data;
}
Сейчас посмотрел на этот код - можно было использовать one-pulse mode. Надо будет переделать.

Это очень интересно. Надо попробовать.

Цитата(KnightIgor @ Jun 30 2016, 14:04) *
А я поставил на плату DS2484R и общаюсь с 1-WIRE по уже отлаженному I2C laughing.gif .

Круто. Не знал что такое есть. Может это действительно решение проблемы.

Цитата(Эдди @ Jun 30 2016, 14:14) *
ТС, возьми нормальную реализацию 1-wire через таймер с DMA и не пугай людей лютым ногодрыгом!
Да и вообще впреть не страдай этой фигней — ногодрыг с паузами через systick... А вдруг паузы нужно будет точные делать, а у тебя в это время прерывание какое-нибудь произойдет? Или будешь все прерывания отключать на время паузы?

Кончай эту аврщину лютую!

Интересно. Но я так понял это для чтения одного датчика? У меня несколько на проводе висят.

Вообще то аппаратное решение проблемы (DS2484) мне кажется лучше всего. Да это увеличение и удорожание платы, но с другой стороны четкая функциональность, разгрузка контроллера, грамотно буферезированный выход. Интересно какая дальнобойность у него. Мне нужно до 300 метров.

Сообщение отредактировал Jenya7 - Jun 30 2016, 09:55
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 30 2016, 10:15
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Jenya7 @ Jun 30 2016, 15:30) *
разгрузка контроллера, грамотно буферезированный выход. Интересно какая дальнобойность у него. Мне нужно до 300 метров.

А чем у Вас контроллер загружен? Другим ногодрыгом? biggrin.gif
Для современных Cortex-M реализация 1-wire посредством прерываний от таймера настолько незначительно нагружает МК, что не стОит навешивания никаких дополнительным чипов.
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jun 30 2016, 12:47
Сообщение #7


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

Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(jcxz @ Jun 30 2016, 14:15) *
А чем у Вас контроллер загружен? Другим ногодрыгом? biggrin.gif
Для современных Cortex-M реализация 1-wire посредством прерываний от таймера настолько незначительно нагружает МК, что не стОит навешивания никаких дополнительным чипов.


Так то оно верно для одного изолированного случая, но когда все выполнено без натяжек, то никогда проблем не возникнет. Тем более, что выбор сделать по-ламерски, потому что думать лень как-то не вселяет оптимизма.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Jenya7   Проблема с функцией задержки.   Jun 27 2016, 09:05
- - scifi   А я вот так сделал: CODE#include "systick.h...   Jun 27 2016, 09:16
|- - Jenya7   Цитата(scifi @ Jun 27 2016, 14:16) А я во...   Jun 27 2016, 09:38
|- - scifi   Цитата(Jenya7 @ Jun 27 2016, 12:38) Я не ...   Jun 27 2016, 11:09
|- - pitt   Цитата(Jenya7 @ Jun 27 2016, 05:38) Я не ...   Jun 27 2016, 13:23
- - KnightIgor   Цитата(Jenya7 @ Jun 27 2016, 10:05) Какая...   Jun 27 2016, 11:35
|- - Jenya7   Цитата(KnightIgor @ Jun 27 2016, 16:35) У...   Jun 27 2016, 12:01
- - Сергей Борщ   Извиняюсь, что не про задержку: QUOTE (Jenya7 ...   Jun 27 2016, 12:45
|- - Jenya7   Цитата(Сергей Борщ @ Jun 27 2016, 17:45) ...   Jun 27 2016, 13:18
|- - Сергей Борщ   QUOTE (Jenya7 @ Jun 27 2016, 16:18) выход...   Jun 27 2016, 13:23
|- - Jenya7   Цитата(Сергей Борщ @ Jun 27 2016, 18:23) ...   Jun 27 2016, 13:28
|- - Сергей Борщ   QUOTE (Jenya7 @ Jun 27 2016, 16:28) Серге...   Jun 27 2016, 13:46
|- - Jenya7   Цитата(Сергей Борщ @ Jun 27 2016, 18:46) ...   Jun 27 2016, 13:54
|- - Сергей Борщ   QUOTE (Jenya7 @ Jun 27 2016, 16:54) После...   Jun 27 2016, 16:13
||- - Jenya7   Цитата(Сергей Борщ @ Jun 27 2016, 21:13) ...   Jun 27 2016, 16:22
||- - Сергей Борщ   QUOTE (Jenya7 @ Jun 27 2016, 19:22) Нижни...   Jun 27 2016, 16:48
||- - Jenya7   Цитата(Сергей Борщ @ Jun 27 2016, 21:48) ...   Jun 27 2016, 16:57
|- - jcxz   Цитата(Jenya7 @ Jun 27 2016, 19:54) Вообщ...   Jun 28 2016, 03:47
- - jcxz   Цитата(Jenya7 @ Jun 27 2016, 15:05) Какая...   Jun 27 2016, 13:44
- - Jenya7   Переделал функции под вариант с OPEN DRAIN. CODE#...   Jun 28 2016, 05:34
|- - Сергей Борщ   QUOTE (Jenya7 @ Jun 28 2016, 08:34) но те...   Jun 28 2016, 07:29
|- - Jenya7   То есть нужно так? Код PIN_OFF(GPIOx, PINx...   Jun 28 2016, 07:44
|- - Alechek   Цитата(Tarbal @ Jun 29 2016, 23:13) Я бол...   Jun 29 2016, 18:42
||- - Tarbal   Цитата(Alechek @ Jun 29 2016, 22:42) И чт...   Jun 29 2016, 20:26
|- - KnightIgor   Цитата(Сергей Борщ @ Jun 30 2016, 09:48) ...   Jun 30 2016, 09:04
|- - Эдди   Цитата(Jenya7 @ Jun 30 2016, 12:30) Интер...   Jun 30 2016, 10:40
- - Эдди   ТС, возьми нормальную реализацию 1-wire через тайм...   Jun 30 2016, 09:14
|- - Сергей Борщ   QUOTE (Эдди @ Jun 30 2016, 12:14) ТС, воз...   Jun 30 2016, 09:43
- - Alechek   Ой, о чем спор? Ногодрыг или аппаратный 1-wire? ...   Jun 30 2016, 11:21
- - Jenya7   Цитата(Alechek @ Jun 30 2016, 16:21) Ой, ...   Jun 30 2016, 12:26
- - Alechek   Цитата(Jenya7 @ Jun 30 2016, 17:26) Я вид...   Jul 1 2016, 04:58


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

 


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


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