141 Востаннє редагувалося ReAl (17.03.2019 16:02:25)

Re: STM32, Atolic TrueStudio, CubeMX

Аналогічно, але це для одного типу і без контролю. Якщо влаштовує, то піде і так.

Універсальний шаблон «форсує» — аргументи мають бути одного типу. Також створює проміжну змінну цього типу.
Тут у макросі typeof створює змінну потрібного типу, а рядок (void)(pa == pb); на етапі компіляції перевіряє сумісність типів.

#define SWAP(pa,pb) \
    do { \
        typeof (*(pa)) __t = *(pa); \
        (void)((pa) == (pb)); \
        *(pa) = *(pb); \
        *(pb) = __t; \
    } while (0)

int a, b;
char c, d;

void foo()
{
    SWAP(&a,&b);
    SWAP(&c,&d);
    SWAP(&a,&d);  // Тут буде помилка компіляції, адреси int і char порівнювати не можна
}

p.s. Ну так, typeof це розширення gcc, але для stm32 це наче не проблема.

Подякували: taburyak, leofun01, fronders3

142

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Аналогічно, але це для одного типу і без контролю.

Щиро дякую. Зрозумів все. Але в функція малювання геометричних фігур де жорстко будуть тіко uint16_t , то вже зайве.

143

Re: STM32, Atolic TrueStudio, CubeMX

Тоді нема проблем з логікою, залишається проблема використання у різних випадках.
Спробуйте скомпілювати

#include <stdint.h>

#define SWAP_INT16_T(a, b) { int16_t t = a; a = b; b = t; }

int p, q, r;

void foo(int i) {
        if (i)
                SWAP_INT16_T(p,q);
        else
                SWAP_INT16_T(p,r);
}

Потім уявіть, як виглядатиме код після підстановки макроса і стане зрозуміло, що у моєму варіанті роблять do { .. } while(0)

Звичайно, можна після макроса не писати ; або завжди брати в {} навіть однорядкові гілки, але це теж криво.
Код, який виглядає «нормально» без знання вунтрішнього облаштування макросу — має компілюватися без помилок компіляції і прихованих проблем.

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

144

Re: STM32, Atolic TrueStudio, CubeMX

Тільки для одного типу. В принципі, можна узагальнити до

#define SWAP( Type, a, b ) { Type t = a; a = b; b = t; }
...
SWAP(int16_t, a, b);

але то справа смаку. Мені в чистих C було б приємніше тут писати обмін руками - узагальнення не настільки суттєве, а ймовірність помилки не зникає.

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

145 Востаннє редагувалося fronders (17.03.2019 15:57:50)

Re: STM32, Atolic TrueStudio, CubeMX

вітаю всіх :)
як на мене, то багатострокові макроси все ж таки краще огортати в конструкцію без крапкокоми

do {
    /* smth */
} while(0)

інакше, як вище вказав ReAl будуть проблеми у випадках коли не ставлять дужки ітд..
краще перестрахуватись заздалегідь
це чудово описано отут на stackoverflow

Подякували: ReAl, koala2

146

Re: STM32, Atolic TrueStudio, CubeMX

До речі:

1. Я там не взяв був параметри макроса у дужки :-), що також треба робити. Виправив.

2. Маючи в руках той таки typeof, макрос є ще куди покращувати. Його можна довести (по виключенню небажаних побічних ефектів) до повної еквівалентності шаблонній inline-функції. Я маю на увазі

int *p, *q;
// ...
SWAP(p++, q++); 

що у даному варіанті макроса матиме руйнівні наслідки.
Тому можна додати локальні у do { } while(0) змінні

#define SWAP(pa,pb) \
    do { \
        typeof (pa) __pa = pa; \
        typeof (pb) __pb = pb; \
        typeof (*__pa) __t = *__pa; \
        (void)(__pa == __pb); \
        *__pa = *__pb; \
        *__pb = __t; \
    } while (0)

і використовувати макрос геть так само, як inline-функцію, не остерігаючись наслідків.

147

Re: STM32, Atolic TrueStudio, CubeMX

У C ніби ж немає type of.

148

Re: STM32, Atolic TrueStudio, CubeMX

koala написав:

У C ніби ж немає type of.

Є як розширення gcc, я про це згадував вище, а також є в clang.
Але gcc так багато де є (скрізь, де є linux, для всього, що на ARM-ах, для деяких дрібніших 16- і 8-бітних мікроконтролерів), що особисто мені можна довго жити без інших компіляторів.

149

Re: STM32, Atolic TrueStudio, CubeMX

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

150 Востаннє редагувалося taburyak (22.04.2019 20:56:46)

Re: STM32, Atolic TrueStudio, CubeMX

Перероблюю 1-wire та DallasTemperature для ардуіни на stm32 і хотів щоб було також перевірка crc.
Сирець:

// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers.  (Use tiny 2x16 entry CRC table)
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
{
    uint8_t crc = 0;

    while (len--) {
        crc = *addr++ ^ crc;  // just re-using crc as intermediate
        crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^
        pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
    }

    return crc;
}

Для STM32:

// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers.  (Use tiny 2x16 entry CRC table)
uint8_t OW_crc8(const uint8_t *addr, uint8_t len)
{
    uint8_t crc = 0;

    while (len--)
    {
        crc = *addr++ ^ crc;  // just re-using crc as intermediate
        crc = (dscrc2x16_table + (crc & 0x0f)) ^ (dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
    }

    return crc;
}

Але компілятор свариться: invalid operands to binary ^ (have 'const uint8_t * {aka const unsigned char *}' and 'const uint8_t * {aka const unsigned char *}')
Я щось не розумію що не так. Підкажіть будь ласка.

151 Востаннє редагувалося ReAl (22.04.2019 21:16:27)

Re: STM32, Atolic TrueStudio, CubeMX

То ж для AVR було, pgm_read_byte приймає адресу байту у флеші і читає звідти байт.

crc = dscrc2x16_table[crc & 0x0f] ^ dscrc2x16_table[16 + ((crc >> 4) & 0x0f))];
Подякували: koala, taburyak, leofun013

152

Re: STM32, Atolic TrueStudio, CubeMX

Ніколи не працював із Arduino, але pgm_read_byte, як я розумію, ніби розіменовує свій параметр (чи з якоїсь там особливої пам'яті читає, чи що). А в другому випадку ви не розіменовуєте.

153

Re: STM32, Atolic TrueStudio, CubeMX

koala написав:

Ніколи не працював із Arduino, але pgm_read_byte, як я розумію, ніби розіменовує свій параметр (чи з якоїсь там особливої пам'яті читає, чи що). А в другому випадку ви не розіменовуєте.

Саме так. AVR «гарвардські», самі 8-бітні, але пам'ять програм 16-бітна на окремій шині і для зчитування з неї констант є геть окремі команди асемблера. То макрос, який робить асм-вставку з потрібною командою.

Подякували: koala, taburyak2

154

Re: STM32, Atolic TrueStudio, CubeMX

Щиро дякую, я навіть зрозумів в чому я помилявся :)

155

Re: STM32, Atolic TrueStudio, CubeMX

Хтось вже пробував Stm32CubeIDE? Знову вискакує одвічна проблема з виводом float у термінал. Шаманство з настройками - не допомагає.

156

Re: STM32, Atolic TrueStudio, CubeMX

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

arm-none-aebi — аналогічно, підтримку floating point потрібно увімкнути на рівні лінкера (scanf ен згадувати, якщо не потрібен).
У мене в Makefile так

    LD_FLAGS    += --specs=nano.specs -Wl,-u,_printf_float,-u,_scanf_float

Все самописне, TrueStudio ніяк не поставлю (з літа я по кісточки — головою вниз — у ядрі лінукса, не до мікроконтролерів).

Дякую за науку. Таки так, перемкнувся з NewLib -nano на NewLib -standart і все запрацювало. Щоправда бінарник потовстішав, але не критично, все має влізти.

У Stm32CubeIDE це не допомагає! В термінал замість "pi=3.14" видає "pi=427698049712233986561263389807651448643933810199578490756492715896724703834878846697472.000000". Не розумію чого...

157

Re: STM32, Atolic TrueStudio, CubeMX

mykyta написав:

У Stm32CubeIDE це не допомагає! В термінал замість "pi=3.14" видає "pi=427698049712233986561263389807651448643933810199578490756492715896724703834878846697472.000000". Не розумію чого...

Тю. Якщо підтримки друку float нема, то воно (не конкретно бібліотека, підключена Stm32CubeIDE, а узагальнене «воно») або нічого не друкує, або одну літерку f від незрозумілого формату.
Це більше схоже на якусь грубу помилку, а не на неправильний варіант бібліотеки.

158

Re: STM32, Atolic TrueStudio, CubeMX

mykyta написав:

Хтось вже пробував Stm32CubeIDE? Знову вискакує одвічна проблема з виводом float у термінал. Шаманство з настройками - не допомагає.

Тут є відповідь.

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

159

Re: STM32, Atolic TrueStudio, CubeMX

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

У Stm32CubeIDE це не допомагає! В термінал замість "pi=3.14" видає "pi=427698049712233986561263389807651448643933810199578490756492715896724703834878846697472.000000". Не розумію чого...

Тю. Якщо підтримки друку float нема, то воно (не конкретно бібліотека, підключена Stm32CubeIDE, а узагальнене «воно») або нічого не друкує, або одну літерку f від незрозумілого формату.
Це більше схоже на якусь грубу помилку, а не на неправильний варіант бібліотеки.

Так і є! Нічого не друкує, коли нічого не шаманить. Таку цмфру починає видавать, коли вручну в настройках починаєш добавлять флаги -u,_printf_float.

160 Востаннє редагувалося taburyak (24.06.2019 07:08:02)

Re: STM32, Atolic TrueStudio, CubeMX

Постанова: поміряти оберти електродвигуна. На валу буде чорна смужка. Зчитуватись буде оптопарою типу модуль датчика перешкод. Це просто для відладки коду і експериментів. На вихлопі може щось буде і інше. Не в цьому питання. А питаннячко саме по таймерам в STM32 та як визначити частоту обертів електродвигуна. На фейсбуці обговорення почав з того, щоб порахувати кількість імпульсів на секунду, але в ході бесіди виявилось що частоту в одиниці кілогерц, краще вимірювати довжину імпульсу, а вже далі порахувати вже скіко то буде в обертах на секунду чи хвилину, то вже не важливо, бо ж питання не в тому. А питання таки як поміряти ту довжину імпульсу за допомоги таймерів STM32. Використовую бібліотеки HAL і генератор ініціалізацій периферії CubeMX. 
Один пан мені порадив зробити так:
Таймер2. режим таймеру:
SlaveMode: reset mode
TriggerSource: TI1FP1
Clock source: internal
Channel1: Input capture direct mode (Це вхід на PA15)
Конфіг таймеру:
prescaler 15 (тактова 16МГц, тобто він рахує ресети кожну 1 мкс)
counter Mode UP
counter period 65535 (максимум)
CKD - none
auto-reload preload enable
slave-mode controller reset mode
Polarity selection Falling edge (тут на який фронт реагує)
NVIC settings: TIM2 global interrupt
Інше by default

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
 {
     if (htim == &htim2)
     {
          if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
          {
               // зчитуємо показник таймера
               lastEvent = __HAL_TIM_GET_COUNTER(htim); 
          }
     }
 }

На початку коду ініціалізую таймер:

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 65535;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
  sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
  sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  sSlaveConfig.TriggerFilter = 0;
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

Запускаю таймер:

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

Та маю такий колбєк:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim2)
    {
        if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
        {
            lastEvent = __HAL_TIM_GET_COUNTER(htim);
        }
    }
}

Все як пан порадив. Але при надходженні імпульсів до 1 каналу TIM2 на PA15 переривань не відбувається.

Вопшем. Допоможіть з цим питанням. Дайте робочий приклад як виміряти довжину імпульсу. Чи ще якось направте в потрібне русло. Дякую.