101

Re: STM32, Atolic TrueStudio, CubeMX

reverse2500 написав:

з власного досвіду, embedded програмування це повний капець, іноді не сходиться те що описано в даташиті, а застосування всі йдуть з іншою маркіровкую чіпа, були такі випадки

Що капєць, то капєць - згоден.

Але ж!!! Той самий сенсор на ESP8266 працює по адресі 0x39, а коли він підключений до STM32 чомусь адреса, чарівним чином в нього вже 0x72 і прекрасно працює. Як тааак??? Два дні в сраку, але ж розібрався.

102

Re: STM32, Atolic TrueStudio, CubeMX

Ще й до того ж, все те саме, на STM32F103 не працює, а на STM32F407 працює. Діла... Залишилось розібратись чи саме на цьому екземплярі STM32F103 не працює, чи то такий драйвер HAL на 10х серії не робочий.

103 Востаннє редагувалося ReAl (18.01.2018 13:45:30)

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Але ж!!! Той самий сенсор на ESP8266 працює по адресі 0x39, а коли він підключений до STM32 чомусь адреса, чарівним чином в нього вже 0x72 і прекрасно працює. Як тааак??? Два дні в сраку, але ж розібрався.

0x72 = 2 * 0x39, я попереджав

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");

104

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

0x72 = 2 * 0x39, я попереджав

Дик, я думав то стосувалось адреси регістрів у сенсорі, а не адреси самого сенсору.
І чо? Це нормально? Просто використовувати адресу 0x72 і не заморочуватись?

105 Востаннє редагувалося taburyak (18.01.2018 14:38:30)

Re: STM32, Atolic TrueStudio, CubeMX

Ага, я мабуть здогадався. Адреса пристроїв складається з 7 бітів. А треба її привести до 8 біт додаючи один розряд шляхом логічного зсуву ліворуч (0x39<<1)? Так?

106

Re: STM32, Atolic TrueStudio, CubeMX

Так, це просто питання вибору абстракції. Одні бібліотеки вважають, що адреса пристрою 7-бітова (як воно і по документації від Філіпса), і ця семибітова адреса розміщується у байті там-то, а молодший біт того байту то зовсім і не адреса.
Інші — де факто у них виходить адреса 8-бітова, пристрій займає дві адреси, одну для запису (що треба для більшості пристроїв зробити і перед зчитуванням для вибору початкової адреси чи регістру) з молодшим бітом 0, одну для зчитування з молодшим бітом 1.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak, 0xDADA11C72

107

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Інші — де факто у них виходить адреса 8-бітова, пристрій займає дві адреси, одну для запису (що треба для більшості пристроїв зробити і перед зчитуванням для вибору початкової адреси чи регістру) з молодшим бітом 0, одну для зчитування з молодшим бітом 1.

Дякую дуже допоміг.

108

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Ще й до того ж, все те саме, на STM32F103 не працює, а на STM32F407 працює. Діла... Залишилось розібратись чи саме на цьому екземплярі STM32F103 не працює, чи то такий драйвер HAL на 10х серії не робочий.

Розібрався. Саме на платі STM32F103RB Nucleo чогось I2C1 не запустився. I2C2 працює чудово. Може якісь особливості саме плати Nucleo і її сумісності по виводам з Arduino.

109

Re: STM32, Atolic TrueStudio, CubeMX

Знову ці вказівники на вказівники і вказівниками поганяють.

Є така функція з бібліотеки про таймери:
Прототип:

/**
 * @brief  Creates a new custom timer which has 1ms resolution
 * @note   It uses @ref malloc for memory allocation for timer structure
 * @param  ReloadValue: Number of milliseconds when timer reaches zero and callback function is called
 * @param  AutoReloadCmd: If set to 1, timer will start again when it reaches zero and callback is called
 * @param  StartTimer: If set to 1, timer will start immediately
 * @param  *TM_DELAY_CustomTimerCallback: Pointer to callback function which will be called when timer reaches zero
 * @param  *UserParameters: Pointer to void pointer to user parameters used as first parameter in callback function
 * @retval Pointer to allocated timer structure
 */
TM_DELAY_Timer_t* TM_DELAY_TimerCreate(uint32_t ReloadValue, uint8_t AutoReloadCmd, uint8_t StartTimer, void (*TM_DELAY_CustomTimerCallback)(struct _TM_DELAY_Timer_t*, void *), void* UserParameters);

Сама функція:

TM_DELAY_Timer_t* TM_DELAY_TimerCreate(uint32_t ReloadValue, uint8_t AutoReloadCmd, uint8_t StartTimer, void (*TM_DELAY_CustomTimerCallback)(struct _TM_DELAY_Timer_t*, void *), void* UserParameters) {
    TM_DELAY_Timer_t* tmp;
    
    /* Check if available */
    if (CustomTimers.Count >= DELAY_MAX_CUSTOM_TIMERS) {
        return NULL;
    }
    
    /* Try to allocate memory for timer structure */
    tmp = (TM_DELAY_Timer_t *) LIB_ALLOC_FUNC(sizeof(TM_DELAY_Timer_t));
    
    /* Check if allocated */
    if (tmp == NULL) {
        return NULL;
    }
    
    /* Fill settings */
    tmp->ARR = ReloadValue;
    tmp->CNT = tmp->ARR;
    tmp->Flags.F.AREN = AutoReloadCmd;
    tmp->Flags.F.CNTEN = StartTimer;
    tmp->Callback = TM_DELAY_CustomTimerCallback;
    tmp->UserParameters = UserParameters;
    
    /* Increase number of timers in memory */
    CustomTimers.Timers[CustomTimers.Count++] = tmp;
    
    /* Return pointer to user */
    return tmp;
}

Структура:

typedef struct _TM_DELAY_Timer_t {
    union {
        struct {            
            uint8_t AREN:1;  /*!< Auto-reload enabled */
            uint8_t CNTEN:1; /*!< Count enabled */
        } F;
        uint8_t FlagsVal;
    } Flags;
    uint32_t ARR;                                        /*!< Auto reload value */
    uint32_t CNT;                                        /*!< Counter value, counter counts down */
    void (*Callback)(struct _TM_DELAY_Timer_t*, void *); /*!< Callback which will be called when timer reaches zero */
    void* UserParameters;                                /*!< Pointer to user parameters used for callback function */
} TM_DELAY_Timer_t;

Що роблю я в коді:
Оголошую структуру таймеру:

TM_DELAY_Timer_t timer;

Створюю функцію зворотнього виклику для таймеру:

void testTimer(void)
{
    LED_RED_TOGGLE();
}

Тепер хочу створити сам таймер:

TM_DELAY_TimerCreate(250, 1, 1, ffff, pppp);

Де 250 - час таймер в мілісеках, 1 - повторювати, 1- негайно, ffff - якось вказати на зворотню функцію з структурою таймера, pppp - якийсь користувацький параметр не зрозумів що за хрінь).

Так ось підкажіть будь ласка як мені правильно записати ffff згідно з наведеною вище функцією (void (*TM_DELAY_CustomTimerCallback)(struct _TM_DELAY_Timer_t*, void *)), і що то за pppp (void* UserParameters)???

110

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Оголошую структуру таймеру:

Нащо? Вона ж створюється в TM_DELAY_TimerCreate.

void ffff(struct _TM_DELAY_Timer_t* my_timer, void *parameters) //параметри не використовуються
{
    testTimer();
}

TM_DELAY_Timer_t *ptimer = TM_DELAY_TimerCreate(250, 1, 1, &ffff, NULL);

taburyak написав:

що то за pppp (void* UserParameters)

вказівник на додаткові параметри, які тут нам ні до чого.

Подякували: taburyak1

111 Востаннє редагувалося taburyak (27.07.2018 13:10:32)

Re: STM32, Atolic TrueStudio, CubeMX

koala написав:

Нащо? Вона ж створюється в TM_DELAY_TimerCreate.

Ну для чогось же ж передбачено ту структуру на вході??? Як це можна використовувати?

koala написав:

вказівник на додаткові параметри, які тут нам ні до чого.

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

А взагалі-то запрацювало!!! Якесь чарівство :) Красно дякую!

112 Востаннє редагувалося ReAl (28.07.2018 12:44:52)

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
koala написав:

Нащо? Вона ж створюється в TM_DELAY_TimerCreate.

Ну для чогось же ж передбачено ту структуру на вході??? Як це можна використовувати?

Ну от дивіться.
Припустимо, Ви хочете керувати _двома_ літніми душами. Але алгоритм один.
Тоді ffff любенько приймає два параметри — вказівник на структуру таймера, який відпрацював, і вказівник на структуру даних (автомата) керування душем.
Тоді

struct douche {
    enum douche_state state;
    TM_DELAY_Timer_t *ptimer;
    uint8_t water_level;
    // що там ще треба
};

struct douche douche1, douche2;

void ffff(struct _TM_DELAY_Timer_t* my_timer, void *parameters)
{
    struct douche *d = (struct douche*)parameters;
    // тепер працюємо з таймером і з полями душа, один і той же таймер в різних
    // станах запрограмований на різний час і означає різне
    switch (d->state) {
    case XXX:
        // ...
        break;

    }    
}

douche1.ptimer = TM_DELAY_TimerCreate(250, 1, 1, &ffff, &douche1);
douche2.ptimer = TM_DELAY_TimerCreate(250, 1, 1, &ffff, &douche2);

а функція ffff подивиться на стан douche, поміняє його як треба при поточному стані і спрацюванні таймера, перезарядить таймер.
Загалом тут є деяка надлишковість, у випадках, коли таке роблять часто, функція таймера часто приймає лише один аргумент
• або вказівник на структуру таймера — і вона сама, а не вказівник на неї, сидить всередині структури об'єкта, тому далі за допомогою магії offsetof і побудованої на її основі магії container_of можна по адресі структури відновити адресу об'єкта
• або вказівник на об'єкт, а функція ffff призначена для роботи з такими об'єктами і тому знає, яке поле таймера цікавить. Тоді у структурі може бути і вказівник на таймер, всі звертання до таймера через d->ptimer
Але тут вирішили, що хай не морочаться з організацією структур, дають два параметри.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak1

113

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Ну от дивіться.
Припустимо, Ви хочете керувати _двома_ літніми душами. Але алгоритм один.

Щиро дякую, друже. Допоміг і направив в потрібне русло.
Наполегливо прошу на "ТИ" звертатись. Це стосується всіх.

114

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Наполегливо прошу на "ТИ" звертатись. Це стосується всіх.

Спробую ;-)

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");

115

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

• або вказівник на структуру таймера — і вона сама, а не вказівник на неї, сидить всередині структури об'єкта, тому далі за допомогою магії offsetof і побудованої на її основі магії container_of можна по адресі структури відновити адресу об'єкта
• або вказівник на об'єкт, а функція ffff призначена для роботи з такими об'єктами і тому знає, яке поле таймера цікавить. Тоді у структурі може бути і вказівник на таймер, всі звертання до таймера через d->ptimer
Але тут вирішили, що хай не морочаться з організацією структур, дають два параметри.

offsetof і container_of в текстах ядра лінукса і пояснення другого на stackoverflow.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak, leofun012

116

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

offsetof і container_of в текстах ядра лінукса і пояснення другого на stackoverflow.

Це по за межами мого всесвіту. Ще не доріс до такого.

117 Востаннє редагувалося ReAl (02.08.2018 07:26:38)

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
ReAl написав:

offsetof і container_of в текстах ядра лінукса і пояснення другого на stackoverflow.

Це по за межами мого всесвіту. Ще не доріс до такого.

А ними можна користуватися як чорними скриньками :-)
Якось так, все умовно.

struct douche {
    enum douche_state state;
    TM_DELAY_Timer_t pump_timer; // вкладена структура, не вказівник!
    TM_DELAY_Timer_t timeout;    // вкладена структура, не вказівник!
    uint8_t water_level;
    // що там ще треба
};
 
struct douche douche1;

void pump_timer_func(TM_DELAY_Timer_t *t)
{
    // Від адреси таймера t віднімаємо зміщення від початку структури
    // struct douche до початку її поля pump_timer. Отримуємо адресу
    // екземпляра структури, у якому лежить цей екземпляр таймера.
    struct douche *d = container_of(t, struct douche, pump_timer);
    switch (d->state) {
    case pump_off:
        pump_power_on();
        timer_start(t, pump_on_time);
        d->state = pump_on;
        break;
    // ...
    }
}

void timeout_func(TM_DELAY_Timer_t *t)
{
    struct douche *d = container_of(t, struct douche, timeout);
    switch (d->state) {
    case pump_on:
        pump_power_off();
        disable_timer(&d->pump_timer);
        d->state = pump_off;
        break;
    // ...
    }
}

// ... 
// а у douche2 інші адреси таймерів всередині цієї структури, бо інша початкова
// адреса самої структури, тому плутанини не буде
// до речі, '&' перед іменем функції геть не обов'язковий (я б навіть сказав, що надлишковий)
    timer_init(&douche1.pump_timer, pump_timer_func);
    timer_init(&douche1.timeout, timeout_func);

    timer_start(&douche1.timeout, 300); // ну чи там як.
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak, leofun012

118

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

А ними можна користуватися як чорними скриньками :-)
Якось так, все умовно.

Оооооо!!! Так я розумію :))) Щира дяка за приклад.

119 Востаннє редагувалося taburyak (19.10.2018 08:51:33)

Re: STM32, Atolic TrueStudio, CubeMX

Всім привіт.

Хотів зформувати рядок тесту з числом float і передати рядок до UART, таким чином:

char bufStr[64];
sprintf(bufStr, "WARNING voltage %s %f", voltageStruct->name, voltageStruct->voltage);
logerUART(bufStr);

але чомусь в uart виводиться все вірно, крім того, що значення float не виводиться взагалі. Неначе там такий рядок:

sprintf(bufStr, "WARNING voltage %s", voltageStruct->name);

Що це за діла? Як мені в рядок вбудувати число float?

120

Re: STM32, Atolic TrueStudio, CubeMX

А буфера точно вистачає?