Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: Мелкие вопросы по МК и ПЛИС.

Пт сен 06, 2019 20:38:36

Что то не пойму:
Перенёс проект из Atollic в IAR и теперь IAR'у не нравится такой #define:
Код:
#define SPI_Tx  while (SPI1->SR & SPI_SR_BSY); SPI1->DR = (uint16_t)

а код такой:
Код:
SPI_Tx (data|0x00);

ошибка такая:
Error[Pe018]: expected a ")" D:\My designs\PJT\IAR\Nokia_1616.c 101


А такой код:
Код:
SPI_Tx 0x11;

его устраивает.

Как переписать дефайн, чтобы заработало?
Макрофункцией? Тоже не работает (data|0x00);
Код:
#define SPI_Tx(cd)  while (SPI1->SR & SPI_SR_BSY); SPI1->DR = (uint16_t)cd

SPI_Tx(0x11);

есть ещё способы?

Спасибо.

Re: Мелкие вопросы по МК и ПЛИС.

Пт сен 06, 2019 21:38:48

Как переписать дефайн, чтобы заработало?
Оба варианта рабочие. Ошибка скорее всего где-то в другом месте по коду выше. Это и есть слабое место макросов - плохо отлаживать. Во втором варианте аргумент cd надо в скобки взять.
Код:
#define SPI_Tx(cd)  while (SPI1->SR & SPI_SR_BSY); SPI1->DR = (uint16_t)(cd)

есть ещё способы?
Функцию надо оформлять функцией и не парить себе мозги.
Код:
static inline void SPI_Tx(uint32_t cd)
{
  while (SPI1->SR & SPI_SR_BSY);
  *(uint16_t *)&SPI1->DR = cd;
}

Обрати внимание, я включил интуицию и предположил, что тебе нужна 16-битная операция записи в регистр SPI->DR. Это делается так как у меня в функции, а не как у тебя в макросе. Ну и (data|0x00) это прикол такой? :)

ЗЫ: На самостоятельную проработку предлагаю подумать что будет с таким применением твоего макроса и функции.
Код:
if(data==0xAA)
  SPI_Tx(data|0x01);
else
  SPI_Tx(data|0x02);
Поэтому макрос вообще правильно вот так
Код:
#define SPI_Tx(cd)  do{while (SPI1->SR & SPI_SR_BSY); SPI1->DR = (uint16_t)(cd);}while(false)
Последний раз редактировалось VladislavS Пт сен 06, 2019 21:49:53, всего редактировалось 1 раз.

Re: Мелкие вопросы по МК и ПЛИС.

Пт сен 06, 2019 21:42:23

а, извиняюсь, чего вы хотели добиться вот этим data|0x00 ?

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 05:36:29

А ещё вот так можно сделать
Код:
template<typename T>
static inline void SPI_Tx(uint32_t data)

  while (SPI1->SR & SPI_SR_BSY);
  *(T*)&SPI1->DR = data;
}
Или даже лучше вот так
Код:
template<typename T>
static inline void SPI_Tx(uint32_t data)

  static_assert(std::is_same_v<T,uint8_t> || std::is_same_v<T,uint16_t>, "User fool");
  while (SPI1->SR & SPI_SR_BSY);
  *(T*)&SPI1->DR = data;
}

Код:
  if(x>255)
    SPI_Tx<uint16_t>(x);
  else
    SPI_Tx<uint8_t>(x);

Всё контролируется и диагностируется на этапе компиляции, всё инлайнится и оптимизируется - красота.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 08:49:14

data|0x00 - по шаблону написал, на время отладки, чтобы не путаться.
Всё оказалось просто - в IAR нет поддержки записи двоичных чисел. GCC судя по всему поддерживает.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 09:08:44

Функцию надо оформлять функцией и не парить себе мозги.
Код:
static inline void SPI_Tx(uint32_t cd)
{
  while (SPI1->SR & SPI_SR_BSY);
  *(uint16_t *)&SPI1->DR = cd;
}

Конечно, только эта функция не рабочая, volatile нельзя пропускать:
Код:
static inline void SPI_Tx(uint32_t cd)
{
  while (SPI1->SR & SPI_SR_BSY) {}
  *(volatile uint16_t*)&SPI1->DR = cd;
}

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 10:34:15

Всё оказалось просто - в IAR нет поддержки записи двоичных чисел. GCC судя по всему поддерживает.
Вот так новость, а мы пользуемся и не подозреваем.

Конечно, только эта функция не рабочая, volatile нельзя пропускать:
Согласен, просто IAR такие вещи "прощает" и при компиляции им эта функция рабочая. А так да, volatile, конечно же.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 11:21:10

а мы пользуемся и не подозреваем.

Я переправил 0b100000000 на 0x100 и заработало, ЧЯДНТ?

(В двоичном виде удобнее менять регистры дисплея, чем писать простыни для изменения пары бит, как это любят делать программеры)

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 11:26:41

Вот кусок из рабочего проекта
Код:
enum class STM32F1_PinMode : uint32_t
{
  NotDefined = 0x12345678,
  // ODR[4] : CNF[3:2] : MODE[1:0]
  Floating                    = 0b0'01'00, // 0x04
  PullUp                      = 0b1'10'00, // 0x18
  PullDown                    = 0b0'10'00, // 0x08
  // Analog mode
  Analog                      = 0b0'00'00, // 0x00
  // Output Open Drain modes
  OpenDrain_LowSpeed          = 0b0'01'10, // 0x06
  OpenDrain_MediumSpeed       = 0b0'01'01, // 0x05
  OpenDrain_HighSpeed         = 0b0'01'11, // 0x07
  // Output Push-Pull modes
  PushPull_LowSpeed           = 0b0'00'10, // 0x02
  PushPull_MediumSpeed        = 0b0'00'01, // 0x01
  PushPull_HighSpeed          = 0b0'00'11, // 0x03
  // Alternate Function Open Drain modes
  AF_OpenDrain_LowSpeed       = 0b0'11'10, // 0x0E
  AF_OpenDrain_MediumSpeed    = 0b0'11'01, // 0x0D
  AF_OpenDrain_HighSpeed      = 0b0'11'11, // 0x0F
  // Alternate Function Push-Pull modes
  AF_PushPull_LowSpeed        = 0b0'10'10, // 0x0A
  AF_PushPull_MediumSpeed     = 0b0'10'01, // 0x09
  AF_PushPull_HighSpeed       = 0b0'10'11  // 0x0B
};
ЧМДНТ?

Попробуй вот это скомпилировать
Код:
int main()
{
  [](){[](){[](){[](){[](){}();}();}();}();}();
  for(;;);
}

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 11:33:21

Всё оказалось просто - в IAR нет поддержки записи двоичных чисел. GCC судя по всему поддерживает.

Не gcc, а С++14.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 12:00:51

Тссс, я плавно подвожу либо к включению С++ режима компилятора, либо обновлению последнего. Но я уже даже забыл когда он С++14 не поддерживал и где такую древнюю версию можно откопать.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 12:40:10

и где такую древнюю версию можно откопать.

С официального сайта с ограничением )

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 12:45:05

Ну версию то хоть озвучь, что-ли...

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 13:18:49

IAR Embedded Workbench for ARM 8.40.1.21539 - свежак ) Ещё мухи не снош..сь!

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 13:26:13

Тогда поставь галку С++ в настройках проекта раз и навсегда и не пудри нам мозги.

Re: Мелкие вопросы по МК и ПЛИС.

Сб сен 07, 2019 14:21:48

Ок, не буду )

Re: Мелкие вопросы по МК и ПЛИС.

Пн сен 09, 2019 05:21:30

*(T*)&SPI1->DR = data;

Потенциальный источник ошибок. Лучше правую часть приводить к левой:
"*(volatile uint16_t*)&SPI1->DR = cd;" => "SPI1->DR = (decltype(SPI1->DR))cd;" или просто "SPI1->DR = (uint16_t)cd;"; эстеты могут использовать static_cast.

Re: Мелкие вопросы по МК и ПЛИС.

Пн сен 09, 2019 13:38:07

Нет, так не прокатит. Регистр SPI_DR чувствителен к разрядности команды записи в него. Правая часть автоматом из uint32_t во время записи командой STRH или STRB обрежется до необходимых 16 и 8 бит.

Насчёт volatile при записи по указателю надо бы стандарт почитать на досуге. Iar, например, "понимает", что если я пишу по указателю, то это не просто так.

Добавлено after 7 hours 2 minutes 45 seconds:
Проделел эксперимент.
Код:
  *(uint8_t *)&SPI1->DR = 0xA0;
  *(uint8_t *)&SPI1->DR = 0xA1;
  *(uint8_t *)&SPI1->DR = 0xA2;
  *const_cast<uint8_t *>((uint8_t *)&SPI1->DR) = 0xA3;
  *const_cast<uint8_t *>((uint8_t *)&SPI1->DR) = 0xA4;
  *const_cast<uint8_t *>((uint8_t *)&SPI1->DR) = 0xA5;
  *(volatile uint8_t *)&SPI1->DR = 0xA6;
  *(volatile uint8_t *)&SPI1->DR = 0xA7;
  *(volatile uint8_t *)&SPI1->DR = 0xA8;
IAR делает 9 операций записи, GCC три. Комментарии излишни.

Re: Мелкие вопросы по МК и ПЛИС.

Пн сен 09, 2019 14:11:10

IAR делает 9 операций записи, GCC три. Комментарии излишни.

Кстати, volatile не работает в constexpr контексте, потому из языка его выпиливают, в С++20 большинство volatile уже deprecated, вместо него предлагают использовать функции volatile_load/store(), как в Rust.

Re: Мелкие вопросы по МК и ПЛИС.

Пн сен 09, 2019 14:20:25

Ну чтож, будем загонять регистры в классы и продолжать пользоваться присваиваниями :)
Ответить