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

 
 
> Проблема с функцией задержки., 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
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 36)
scifi
сообщение Jun 27 2016, 09:16
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



А я вот так сделал:
CODE
#include "systick.h"
#include "stm32f0xx.h"

void
systick_init(void)
{
SysTick->CTRL &= SysTick_CTRL_ENABLE_Msk; // stop SysTick timer
SysTick->LOAD = 0x00FFFFFF;
SysTick->VAL = 0x00FFFFFF;
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk; // start SysTick timer
}

int
systick_ticks(void)
{
return SysTick->VAL;
}

int
systick_diff(int from, int to)
{
return (from - to) & 0x00FFFFFF;
}

void
systick_delay(int ticks)
{
int start = systick_ticks();
while (systick_diff(start, systick_ticks()) < ticks) ;
}
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 27 2016, 09:38
Сообщение #3


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

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



Цитата(scifi @ Jun 27 2016, 14:16) *
А я вот так сделал:

Я не хочу чтоб он все время тикал, будет генерироваться интерапт который не нужен (SysTick_Handler). А так открыл, отсчитал, закрыл.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 27 2016, 11:09
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Jenya7 @ Jun 27 2016, 12:38) *
Я не хочу чтоб он все время тикал, будет генерироваться интерапт который не нужен (SysTick_Handler).

Не пойму, кому это может помешать. Можно подумать, кто-то держит у виска пистолет и заставляет обрабатывать все запросы на прерывание.
Впрочем, хозяин - барин.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Jun 27 2016, 11:35
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Jenya7 @ Jun 27 2016, 10:05) *
Какая то ну очень странная проблема.
Я сделал функцию задержки так.

Уже неоднократно обсуждалось и предлагалось, как тут.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 27 2016, 12:01
Сообщение #6


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

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



Цитата(KnightIgor @ Jun 27 2016, 16:35) *
Уже неоднократно обсуждалось и предлагалось, как тут.

спасибо поробую с DWT. В EFM32 я делал на нем задержки все работало хорошо. Что интересно - сделал задержку на таймере и вышеуказанная функция заработала. Вижу ожидаемые 480 микро. Интересно почему SysTick так себя ведет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 12:45
Сообщение #7


Гуру
******

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



Извиняюсь, что не про задержку:
QUOTE (Jenya7 @ Jun 27 2016, 12:05) *
CODE
unsigned int One_Wire_Reset(GPIO_TypeDef * GPIOx, uint16_t PINx)
{
    ...
    PIN_OUT_PP(GPIOx, PINx);
    ...
Вы хорошо подумали?


--------------------
На любой вопрос даю любой ответ
"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 27 2016, 13:18
Сообщение #8


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

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



Цитата(Сергей Борщ @ Jun 27 2016, 17:45) *
Извиняюсь, что не про задержку:
Вы хорошо подумали?

Пин работает в двух режимах - выход пуш-пул на передачу и вход на прием.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 13:23
Сообщение #9


Гуру
******

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



QUOTE (Jenya7 @ Jun 27 2016, 16:18) *
выход пуш-пул на передачу
Вы уверены, что он должен передавать именно в этом режиме?


--------------------
На любой вопрос даю любой ответ
"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
pitt
сообщение Jun 27 2016, 13:23
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



Цитата(Jenya7 @ Jun 27 2016, 05:38) *
Я не хочу чтоб он все время тикал, будет генерироваться интерапт который не нужен (SysTick_Handler). А так открыл, отсчитал, закрыл.

STM32F4xx
Код
#define DWT_CYCCNT    *(volatile uint32_t *)0xE0001004
#define DWT_CONTROL   *(volatile uint32_t *)0xE0001000
#define SCB_DEMCR     *(volatile uint32_t *)0xE000EDFC
  
#ifndef HCLK
  #define   HCLK      168000000
#endif

#define dwt_ena()     (SCB_DEMCR   |=  CoreDebug_DEMCR_TRCENA_Msk)
#define dwt_dis()     (SCB_DEMCR   &= ~CoreDebug_DEMCR_TRCENA_Msk)
#define dwt_rst()     DWT_CYCCNT    = 0
#define dwt_start()   (DWT_CONTROL |= DWT_CTRL_CYCCNTENA_Msk)
#define dwt_cnt()     DWT_CYCCNT

void delay_1us (void) {
  uint32_t start, end;
  
  start = dwt_cnt();
  end = start + HCLK/1000000;
  if (end < start) while (dwt_cnt() > start);
  while (end >= dwt_cnt());
}

void delay_1ms (void) {
  uint32_t start, end;
  
  start = dwt_cnt();
  end = start + HCLK/1000;
  if (end < start) while (dwt_cnt() > start);
  while (end >= dwt_cnt());


Идея, надеюсь, понятна...


--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 27 2016, 13:28
Сообщение #11


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

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



Цитата(Сергей Борщ @ Jun 27 2016, 18:23) *
Вы уверены, что он должен передавать именно в этом режиме?

Сергей что вы такой загадочный. sm.gif А в каком же еще режиме ему передавать? У меня внешняя подтяжка.

Цитата(pitt @ Jun 27 2016, 18:23) *
Идея, надеюсь, понятна...

Спасибо. Сделаю на DWT.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 27 2016, 13:44
Сообщение #12


Гуру
******

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



Цитата(Jenya7 @ Jun 27 2016, 15:05) *
Какая то ну очень странная проблема.
SysTick->LOAD = ticks;
SysTick->CTRL |= 0x01; //enable
while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL &= ~0x01; //disable

Хотя-бы откройте даташит с описанием Systick!
Почему SysTick->CTRL |= 0x01 ??? Почему текущее значение не сбрасываете? Почему флаг предварительно не чистите? ....
А что у Вас в остальных битах? А бит 1? Может у вас там ISR вызывается? А бит 2? Какой частотой тактируется Systick? Что за магическое число 72? Если хотите тактироваться частотой ядра, то нужно:
Код
SysTick->CTRL = 1 << 2;
u32 j = SysTick->CTRL;
SysTick->LOAD = SysTick->CURRENT = ticks;
SysTick->CTRL = 1 | 1 << 2;
while (!(SysTick->CTRL & 1 << 16));
SysTick->CTRL = 1 << 2;  //disable
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 13:46
Сообщение #13


Гуру
******

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



QUOTE (Jenya7 @ Jun 27 2016, 16:28) *
Сергей что вы такой загадочный. sm.gif А в каком же еще режиме ему передавать? У меня внешняя подтяжка.
Точно в таком же, как и в I2C - в режиме открытого коллектора. Во-первых, на шине не будет конфликта уровней, когда датчик уже начал отвечать, а вы еще не начали его слушать. Во-вторых, не нужно будет вообще менять режим ноги, потому что ногу в режиме открытого коллектора можно читать не меняя режима (отключив нижний транзистор, т.е. выдав единицу).


--------------------
На любой вопрос даю любой ответ
"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 27 2016, 13:54
Сообщение #14


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

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



Цитата(Сергей Борщ @ Jun 27 2016, 18:46) *
Точно в таком же, как и в I2C - в режиме открытого коллектора. Во-первых, на шине не будет конфликта уровней, когда датчик уже начал отвечать, а вы еще не начали его слушать. Во-вторых, не нужно будет вообще менять режим ноги, потому что ногу в режиме открытого коллектора можно читать не меняя режима (отключив нижний транзистор, т.е. выдав единицу).

Спасибо. Не знал.
Последнее я не понял. Что значит выдав единицу? Это на выход?

Цитата(jcxz @ Jun 27 2016, 18:44) *
Хотя-бы откройте даташит с описанием Systick!
Почему SysTick->CTRL |= 0x01 ??? Почему текущее значение не сбрасываете? Почему флаг предварительно не чистите? ....
А что у Вас в остальных битах? А бит 1? Может у вас там ISR вызывается? А бит 2? Какой частотой тактируется Systick? Что за магическое число 72? Если хотите тактироваться частотой ядра, то нужно:
Код
SysTick->CTRL = 1 << 2;
u32 j = SysTick->CTRL;
SysTick->LOAD = SysTick->CURRENT = ticks;
SysTick->CTRL = 1 | 1 << 2;
while (!(SysTick->CTRL & 1 << 16));
SysTick->CTRL = 1 << 2;  //disable

Мда...Точно. Спасибо.
Вообще то это не disable SysTick->CTRL = 1 << 2; а выбор источника тактирования...ну и disable тоже.

Сообщение отредактировал Jenya7 - Jun 27 2016, 14:39
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 16:13
Сообщение #15


Гуру
******

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



QUOTE (Jenya7 @ Jun 27 2016, 16:54) *
Последнее я не понял. Что значит выдав единицу? Это на выход?
Ну да. Верхний транзистор при настройке выхода в режим открытого стока отключается совсем. При выводе нуля включается нижний транзистор, на выходе появляется ноль. При выводе единицы нижний транзистор отключается, выход оказывается в третьем состоянии и притягивается к единице внешним резистором. Вот в это время ногу и можно читать - если никто другой не притянул ее к земле своим открытым стоком/коллектором, то с нее прочитается единица. Если притянул - соответственно, ноль.


--------------------
На любой вопрос даю любой ответ
"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 27 2016, 16:22
Сообщение #16


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

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



Цитата(Сергей Борщ @ Jun 27 2016, 21:13) *
Ну да. Верхний транзистор при настройке выхода в режим открытого стока отключается совсем. При выводе нуля включается нижний транзистор, на выходе появляется ноль. При выводе единицы нижний транзистор отключается, выход оказывается в третьем состоянии и притягивается к единице внешним резистором. Вот в это время ногу и можно читать - если никто другой не притянул ее к земле своим открытым стоком/коллектором, то с нее прочитается единица. Если притянул - соответственно, ноль.

Нижний транзистор n-mos, по идее на единице он должен открыться.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 16:48
Сообщение #17


Гуру
******

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



QUOTE (Jenya7 @ Jun 27 2016, 19:22) *
Нижний транзистор n-mos, по идее на единице он должен открыться.
И что при этом будет на выходе?


--------------------
На любой вопрос даю любой ответ
"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 27 2016, 16:57
Сообщение #18


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

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



Цитата(Сергей Борщ @ Jun 27 2016, 21:48) *
И что при этом будет на выходе?

Понял. Большое спасибо. Этот метод конечно гораздо лучше. Завтра попробую.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 28 2016, 03:47
Сообщение #19


Гуру
******

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



Цитата(Jenya7 @ Jun 27 2016, 19:54) *
Вообще то это не disable SysTick->CTRL = 1 << 2; а выбор источника тактирования...ну и disable тоже.

Вообще-то это как раз disable, так как предыдущее значение регистра известно и какой смысл тогда в команде чтения-модификации-записи? Добавить лишнюю команду чтения?
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 28 2016, 05:34
Сообщение #20


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

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



Переделал функции под вариант с OPEN DRAIN.
CODE
#define OPEN_DRAIN 1

unsigned int One_Wire_Reset(GPIO_TypeDef * GPIOx, uint16_t PINx)
{
#if OPEN_DRAIN
unsigned int tmp;
PIN_ON(GPIOx, PINx);
if ((PIN_SYG(GPIOx, PINx))==0) return One_Wire_Bus_Low_Error;

PIN_OFF(GPIOx, PINx);
TIM6_Delay_us(480);
PIN_ON(GPIOx, PINx);
TIM6_Delay_us(60);

if ((PIN_SYG(GPIOx, PINx))==0) tmp=One_Wire_Success;
else tmp=One_Wire_Error_No_Echo;
TIM6_Delay_us(350);
return tmp;
#else
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);
TIM6_Delay_us(480);
PIN_ON(GPIOx, PINx);
PIN_IN(GPIOx, PINx);
TIM6_Delay_us(60);

if ((PIN_SYG(GPIOx, PINx))==0) tmp=One_Wire_Success;
else tmp=One_Wire_Error_No_Echo;
TIM6_Delay_us(350);
return tmp;
#endif
}

void One_Wire_Write_Byte(unsigned char Byte,GPIO_TypeDef * GPIOx, uint16_t PINx)
{
unsigned char cnt;
for (cnt=0;cnt!=8;cnt++)
One_Wire_Write_Bit(Byte&(1<<cnt),GPIOx, PINx);
}

void One_Wire_Write_Bit (unsigned char Bit, GPIO_TypeDef * GPIOx, uint16_t PINx)
{
#if OPEN_DRAIN
PIN_OFF(GPIOx, PINx);
if (Bit==0)
{
TIM6_Delay_us(60);
PIN_ON(GPIOx, PINx);
TIM6_Delay_us(10);
}
else
{
TIM6_Delay_us(10);
PIN_ON(GPIOx, PINx);
TIM6_Delay_us(60);
}
#else
PIN_OUT_PP(GPIOx, PINx);
PIN_OFF(GPIOx, PINx);
if (Bit==0)
{
//Delay_us(Time_Pulse_Delay_High);
TIM6_Delay_us(60);
PIN_ON(GPIOx, PINx);
//Delay_us(Time_Pulse_Delay_Low)
TIM6_Delay_us(10);
}
else
{
TIM6_Delay_us(10);
PIN_ON(GPIOx, PINx);
TIM6_Delay_us(60);
}
PIN_IN(GPIOx, PINx);
#endif
}

unsigned char One_Wire_Read_Byte(GPIO_TypeDef * GPIOx, uint16_t PINx)
{
unsigned char tmp=0;
unsigned char cnt;
for (cnt=0;cnt!=8;cnt++)
if (One_Wire_Read_Bit(GPIOx, PINx)!=0) tmp|=(1<<cnt);
TIM6_Delay_us(60);
return tmp;
}

unsigned char One_Wire_Read_Bit (GPIO_TypeDef * GPIOx, uint16_t PINx)
{
#if OPEN_DRAIN
unsigned char tmp;
PIN_OFF(GPIOx, PINx);
TIM6_Delay_us(2);
TIM6_Delay_us(10);
if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1;
else tmp = 0;
TIM6_Delay_us(60);
return tmp;
#else
unsigned char tmp;
PIN_OUT_PP(GPIOx, PINx);
PIN_OFF(GPIOx, PINx);
TIM6_Delay_us(2);
PIN_IN(GPIOx, PINx);
TIM6_Delay_us(10);
if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1;
else tmp = 0;
TIM6_Delay_us(60);
return tmp;
#endif
}

Что то не работает. Хотя на скопе вижу рисет корректный но температура и серийный номер не читаются. В старом варианте (OPEN_DRAIN 0) все работает.

Сообщение отредактировал Jenya7 - Jun 28 2016, 05:35
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 28 2016, 07:29
Сообщение #21


Гуру
******

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



QUOTE (Jenya7 @ Jun 28 2016, 08:34) *
но температура и серийный номер не читаются. В старом варианте (OPEN_DRAIN 0) все работает.

Сравните:
CODE
    PIN_OUT_PP(GPIOx, PINx);
    PIN_OFF(GPIOx, PINx);
    TIM6_Delay_us(2);
    PIN_IN(GPIOx, PINx);                  // <-- обратите внимание, тут нога перешла на ввод
    TIM6_Delay_us(10);
    if ((PIN_SYG(GPIOx, PINx))!=0)    tmp = 1;
}

и
CODE
    PIN_OFF(GPIOx, PINx);
    TIM6_Delay_us(2);
    TIM6_Delay_us(10);                  // а тут она осталась притянутой к нулю
    if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1;


--------------------
На любой вопрос даю любой ответ
"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 28 2016, 07:44
Сообщение #22


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

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



То есть нужно так?
Код
    PIN_OFF(GPIOx, PINx);
    TIM6_Delay_us(2);
    PIN_ON(GPIOx, PINx);
    TIM6_Delay_us(10);                  // а тут она осталась притянутой к нулю
    if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1;


Да! Работает! И даже считывает два датчика. Громадное спасибо! sm.gif

Сообщение отредактировал IgorKossak - Jun 28 2016, 15:43
Причина редактирования: бездумное цитирование
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jun 29 2016, 18:13
Сообщение #23


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

Группа: Свой
Сообщений: 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
Alechek
сообщение Jun 29 2016, 18:42
Сообщение #24


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

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



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

И что с того? Если время идет на микросекунды?
Для справки, на LPC21xx 48 МГц переключение контекста FreeRTOS занимает 2.2 мкс.

Здесь задержки, судя по коду, 2 и 10 мкс. Стоит ли овчинка выделки?
Единственое, в Delay можно добавить WFI, чтобы чуток меньше энергии кушалось.
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jun 29 2016, 20:26
Сообщение #25


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

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



Цитата(Alechek @ Jun 29 2016, 22:42) *
И что с того? Если время идет на микросекунды?
Для справки, на LPC21xx 48 МГц переключение контекста FreeRTOS занимает 2.2 мкс.

Здесь задержки, судя по коду, 2 и 10 мкс. Стоит ли овчинка выделки?
Единственое, в Delay можно добавить WFI, чтобы чуток меньше энергии кушалось.


Ну если короткие то можно смириться.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 30 2016, 08:05
Сообщение #26


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

Группа: Участник
Сообщений: 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
Сообщение #27


Гуру
******

Группа: Модераторы
Сообщений: 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
KnightIgor
сообщение Jun 30 2016, 09:04
Сообщение #28


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Сергей Борщ @ Jun 30 2016, 09:48) *
Я делал на одном прерывани таймера, использовал три модуля захвата/сравнения (Capture/Compare) и событие переполнения (UIF) таймера.

А я поставил на плату DS2484R и общаюсь с 1-WIRE по уже отлаженному I2C laughing.gif .
Go to the top of the page
 
+Quote Post
Эдди
сообщение Jun 30 2016, 09:14
Сообщение #29


Знающий
****

Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250



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

Кончай эту аврщину лютую!
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 30 2016, 09:30
Сообщение #30


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

Группа: Участник
Сообщений: 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
Сергей Борщ
сообщение Jun 30 2016, 09:43
Сообщение #31


Гуру
******

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



QUOTE (Эдди @ Jun 30 2016, 12:14) *
ТС, возьми нормальную реализацию 1-wire через таймер с DMA
Таймер, ПДП и нога, на которую вешается линия прибиты гвоздями, частота таймера тоже прибита гвоздями, куча #define в заголовочном файле, совершенно не нужных никому, кроме самого файла реализации - "нормальная" реализация, ничего не скажешь sm.gif Но сама идея неплоха.


--------------------
На любой вопрос даю любой ответ
"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
jcxz
сообщение Jun 30 2016, 10:15
Сообщение #32


Гуру
******

Группа: Свой
Сообщений: 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
Эдди
сообщение Jun 30 2016, 10:40
Сообщение #33


Знающий
****

Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250



Цитата(Jenya7 @ Jun 30 2016, 12:30) *
Интересно. Но я так понял это для чтения одного датчика?

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

Совершенно бесмысленно это: вместо одной ноги МК занятыми будут две; все равно нужно будет как-то общаться с внешним драйвером (либо блокирующе, либо через DMA)...
А это решение ни контроллер не нагружает (т.к. DMA спокойненько работает отдельно от основного функционала), ни удорожает. Разве что после получения флага готовности очередной порции данных нужно их обработать (один байт данных == массив из восьми uint16_t)...

Цитата(Сергей Борщ @ Jun 30 2016, 12:43) *
Таймер, ПДП и нога, на которую вешается линия прибиты гвоздями, частота таймера тоже прибита гвоздями...

Другой вариант — таймер с прерываниями. Это менее красивое решение, но тоже сойдет.
А ногодрыг - для ардуйщиков поганых.

Насчет "прибивания гвоздями" — можно дефайнами сделать, но это только увеличит шанс ошибиться. Лучше перепроверить в случае выбора другого таймера все по даташиту и поменять непосредственно в сишном файле.
Понятно, что рабочая частота тоже может быть не 72МГц — соответственно надо вносить изменения.
Я не собирался делать "скетч для ардуйни", поэтому ничего лишнего не пихал в код.
Go to the top of the page
 
+Quote Post
Alechek
сообщение Jun 30 2016, 11:21
Сообщение #34


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

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



Ой, о чем спор? Ногодрыг или аппаратный 1-wire? smile3009.gif
Так он прекрасно реализовывается хоть на UART хоть на SPI. disco.gif
ТС хочет извращаться - пускай занимается извратом. Поможем ему по теме! cool.gif
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jun 30 2016, 12:26
Сообщение #35


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

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



Цитата(Alechek @ Jun 30 2016, 16:21) *
Ой, о чем спор? Ногодрыг или аппаратный 1-wire? smile3009.gif
Так он прекрасно реализовывается хоть на UART хоть на SPI. disco.gif
ТС хочет извращаться - пускай занимается извратом. Поможем ему по теме! cool.gif

Я видел реализацию на ЮАРТ. Мне понравилось. Боюсь что свободных ЮАРТов у меня не останеться.
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jun 30 2016, 12:47
Сообщение #36


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

Группа: Свой
Сообщений: 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
Alechek
сообщение Jul 1 2016, 04:58
Сообщение #37


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

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



Цитата(Jenya7 @ Jun 30 2016, 17:26) *
Я видел реализацию на ЮАРТ. Мне понравилось. Боюсь что свободных ЮАРТов у меня не останеться.

Ага, и с SPI напряг... Слабо верится.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 4th September 2025 - 20:37
Рейтинг@Mail.ru


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