Страница 69 из 130

Re: Программирование STM8

Добавлено: Пт дек 02, 2016 21:13:00
Jeka_M
Читаю reference manual на stm8s, раздел по таймерам. Вот написано, что у advanced control timer прескалер может быть: any integer from 1 to 65536. То есть, любое целое число в диапазоне 1 - 65536. Это понятно. А вот у general purpose timer прескалер может быть: any power of 2 from 1 to 32768. Тут непонятка. Имеется в виду число кратное двойке - 2, 4, 6, 8, 10, 12... или степень двойки - 2, 4, 8, 16, 32, 64 ?

UPD: Блин, туплю... "power of 2" - это же степень двойки? Получается всего 16 значений от 1 до 32768.
UPD2: Ага. И записывается в регистр не само значение прескалера (как в advanced control timer), а степень двойки. Например для прескалера 128 нужно записать 7 в регистр, т.к. 2^7=128

Re: Программирование STM8

Добавлено: Вс дек 04, 2016 21:40:10
Jeka_M
Эм... А кто-нибудь сталкивался с таким: на STM8S003F3 почему-то не работают внутренние подтягивающие резисторы. Конфигурирую пины PB4, PB5 в IAR:

Код: Выделить всё

PB_DDR_bit.DDR4 = 0;// PB4 Input
PB_DDR_bit.DDR5 = 0;// PB5 Input

PB_CR1_bit.C14 = 1; // PB4 Input with pull-up
PB_CR1_bit.C15 = 1; // PB5 Input with pull-up

PB_CR2_bit.C24 = 0; // PB4 EXTI disabled
PB_CR2_bit.C25 = 0; // PB5 EXTI disabled
Проверяю в дебагере, биты C14 и C15 в регистре PB_CR1 устанавливаются в единицу. Но не смотря на это, биты IDR4 и IDR5 в регистре PB_IDR хаотично переключаются. Когда ставлю внешний подтягивающий резистор - всё работает. Не пойму, что не так. То ли я где-то косячу, то ли что-то с МК. В Errata Sheet заглядывал, там про pull-up ничего не сказано.

Re: Программирование STM8

Добавлено: Вс дек 04, 2016 21:50:34
Z_h_e
Кажется эти выхода true open drain.

Re: Программирование STM8

Добавлено: Пн дек 05, 2016 01:00:42
Jeka_M
Точно, спасибо!

Сначала было подумал, каким боком true open-drain, если используется режим входа? Но потом внимательно посмотрел даташит и таки да: PB4 и PB5 - true open-drain. А чуть ниже пометка: "P-buffer, weak pull-up, and protection diode to VDD are not implemented". И это два единственных пина с true open-drain.

Всё никак не привыкну после AVR, что у STM надо обращать внимание на особенности разных ножек.

Re: Программирование STM8

Добавлено: Пн дек 05, 2016 07:36:34
GARMIN
Так у них может быть питание 3,3В, а работают с I2C устройством от 5В. Вот в этом случае open drain выручает.
Мне как раз понадобился такой режим - настройка внешнего устройства по I2C.

Re: Программирование STM8

Добавлено: Ср дек 07, 2016 23:13:09
ptr128
Разбираюсь с STM8S_StdPeriph_Lib
Файл stm8s_tim2.h, начиная со строки 251:

Код: Выделить всё

/** TIM2 Flags */
typedef enum
{
  TIM2_FLAG_UPDATE                   = ((uint16_t)0x0001),
  TIM2_FLAG_CC1                      = ((uint16_t)0x0002),
  TIM2_FLAG_CC2                      = ((uint16_t)0x0004),
  TIM2_FLAG_CC3                      = ((uint16_t)0x0008),
  TIM2_FLAG_CC1OF                    = ((uint16_t)0x0200),
  TIM2_FLAG_CC2OF                    = ((uint16_t)0x0400),
  TIM2_FLAG_CC3OF                    = ((uint16_t)0x0800)
}TIM2_FLAG_TypeDef;
Файл stm8s_tim2.c, функция TIM2_ClearFlag, строка 1110:

Код: Выделить всё

TIM2->SR2 = (uint8_t)(~((uint8_t)((uint8_t)TIM2_FLAG >> 8)));
У меня устойчивое ощущение, что должно быть:

Код: Выделить всё

TIM2->SR2 = (uint8_t)(~((uint8_t)(TIM2_FLAG >> 8)));

Re: Программирование STM8

Добавлено: Чт дек 08, 2016 12:40:01
john1770
Все правильно сначала сдвинуть потом преобразовать
иначе будет ноль

Re: Программирование STM8

Добавлено: Пт дек 09, 2016 20:09:33
GARMIN
ptr128 писал(а):Разбираюсь с STM8S_StdPeriph_Lib

Код: Выделить всё

/** TIM2 Flags */
typedef enum
{
  TIM2_FLAG_UPDATE                   = ((uint16_t)0x0001),
  TIM2_FLAG_CC1                      = ((uint16_t)0x0002),
  TIM2_FLAG_CC2                      = ((uint16_t)0x0004),
  TIM2_FLAG_CC3                      = ((uint16_t)0x0008),
  TIM2_FLAG_CC1OF                    = ((uint16_t)0x0200),
  TIM2_FLAG_CC2OF                    = ((uint16_t)0x0400),
  TIM2_FLAG_CC3OF                    = ((uint16_t)0x0800)
}TIM2_FLAG_TypeDef;
Боже, это написано для 8-ми битного процессора? Там же два восьмибитных регистра:

Код: Выделить всё

/*SR1*/
#define TIM2_SR1_CC3IF   ((uint8_t)0x08) /*!< Capture/Compare 3 Interrupt Flag mask. */
#define TIM2_SR1_CC2IF   ((uint8_t)0x04) /*!< Capture/Compare 2 Interrupt Flag mask. */
#define TIM2_SR1_CC1IF   ((uint8_t)0x02) /*!< Capture/Compare 1 Interrupt Flag mask. */
#define TIM2_SR1_UIF     ((uint8_t)0x01) /*!< Update Interrupt Flag mask. */
/*SR2*/
#define TIM2_SR2_CC3OF   ((uint8_t)0x08) /*!< Capture/Compare 3 Overcapture Flag mask. */
#define TIM2_SR2_CC2OF   ((uint8_t)0x04) /*!< Capture/Compare 2 Overcapture Flag mask. */
#define TIM2_SR2_CC1OF   ((uint8_t)0x02) /*!< Capture/Compare 1 Overcapture Flag mask. */
Обращение проще пареной репы

Код: Выделить всё

TIM2->SR2 &= ~TIM2_SR2_CC3OF
Зачем удалять гланды через задний проход?

Re: Программирование STM8

Добавлено: Пт дек 09, 2016 21:00:47
ptr128
Так как автор кода ST, могу только предположить, что это было сделано, чтобы получить одну функцию. У Вас же получается две. В любом случае, SDCC впихнуло параметр в 16-ти битный регистр, так что по производительности вариант ST ничем не хуже Вашего.

А как по мне, такие вещи вообще правильней макросами делать без лишних функций.

Re: Программирование STM8

Добавлено: Пт дек 09, 2016 21:10:58
a5021
ptr128 писал(а):Так как автор кода ST, могу только предположить, что это было сделано, чтобы получить одну функцию.
Функция может быть и ни при чем, если вспомнить, что SR1 и SR2 отображаются в адресном пространстве по соседству и к ним обоим можно обращаться сразу, как к одному 16-битному регистру.

Re: Программирование STM8

Добавлено: Сб дек 10, 2016 03:18:02
ptr128
Вспоминать можно что угодно, но в
ptr128 писал(а):STM8S_StdPeriph_Lib TIM2_ClearFlag
выполнена функцией.

Re: Программирование STM8

Добавлено: Сб дек 10, 2016 17:12:18
a5021
И что дальше? Вы предлагаете писанину обдолбанных индусов возвести в ранг эталона и молиться на нее, как на сокровищницу программистской мысли? Код STM8S_StdPeriph_Lib местами вообще напоминает плоды программы социализации больных с тяжелыми формами аутизма. Типа, пусть они пишут, чего им вздумается, ST Micro выкладывает это в паблик, чтобы у больных создавалось ощущение востребованности плодов их труда. Как либо иначе объяснить всю эту долбанину исключительно сложно.

Любопытства ради, я просмотрел сейчас код в stm8s_tim2 и испытал совершенно непередаваемые ощущения. Позволю себе привести один маленький фрагмент, чтобы не быть голословным:

Код: Выделить всё

FlagStatus TIM2_GetFlagStatus(TIM2_FLAG_TypeDef TIM2_FLAG)
{
  FlagStatus bitstatus = RESET;
  uint8_t tim2_flag_l = 0, tim2_flag_h = 0;
  
  /* Check the parameters */
  assert_param(IS_TIM2_GET_FLAG_OK(TIM2_FLAG));
  
  tim2_flag_l = (uint8_t)(TIM2->SR1 & (uint8_t)TIM2_FLAG);
  tim2_flag_h = (uint8_t)((uint16_t)TIM2_FLAG >> 8);
  
  if ((tim2_flag_l | (uint8_t)(TIM2->SR2 & tim2_flag_h)) != (uint8_t)RESET )
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return (FlagStatus)bitstatus;
}
Начинаем разматывать этот бред с конца: функция, возвращающая результат типа FlagStatus, оператором Return описывает возврат значения переменной типа FlagStatus. Вопрос: в какой из самых запущенных стадий находится помутнение рассудка у писавшего сие, если он отдельно описывает приведение переменной типа FlagStatus к типу FlagStatus ?

Следующий момент: в секции else переменной bitstatus присваивается значение RESET. Смотрим внимательно, могла ли эта переменная иметь другое значение, если известно, что в самой первой строке функции именно это значение ей и присваивалось, а более никаких действий с этой переменной в коде функции не производится? На кой хрен вообще нужна секция else в таком случае?

Чтобы разобрать загадочные манипуляции с двумя переменными, не хватит ни времени ни страниц форума. Охарактеризую коротко -- это жесточайшая шизофрения, невиданная и непостижимая.

Как говорится, "критикуя, предлагай". Что бы написал я, если бы данный кусок кода поручили придумывать мне. Начну по порядку: тип для отображения статуса таймера я бы объявил так:

Код: Выделить всё

/** TIM2 Flags */
typedef enum
{
  TIM2_FLAG_UPDATE                   = ((uint16_t)(TIM2_SR1_UIF * 256)),
  TIM2_FLAG_CC1                      = ((uint16_t)(TIM2_SR1_CC1IF * 256)),
  TIM2_FLAG_CC2                      = ((uint16_t)(TIM2_SR1_CC2IF * 256)),
  TIM2_FLAG_CC3                      = ((uint16_t)(TIM2_SR1_CC3IF * 256)),
  TIM2_FLAG_CC1OF                    = ((uint16_t)(TIM2_SR2_CC1OF)),
  TIM2_FLAG_CC2OF                    = ((uint16_t)(TIM2_SR2_CC2OF)),
  TIM2_FLAG_CC3OF                    = ((uint16_t)(TIM2_SR2_CC3OF))
}TIM2_FLAG_TypeDef;
Разницу с тем, как это объявлено в STM8S_StdPeriph_Lib у буйнопомешанных индусов, представляет иной порядок размещения флагов. По сути, он обратный: флаги SR1 лежат в старшем байте, флаги SR2 в младшем. Вместо волшебных цифр, дифайны из stm8s.h

Что дает такая "перемена мест слагаемых": если переменную данного типа мысленно наложить на TIM2_SR1, то члены перечисления точно лягут по флагам того же назначения, как в регистрах TIM2->SR1 и TIM2->SR2. Это в свою очередь позволит упростить такие функции, как TIM2_ClearFlag и TIM2_GetFlagStatus. Они легко могут быть переписаны в каком-то таком виде:

Код: Выделить всё

void TIM2_ClearFlag(TIM2_FLAG_TypeDef TIM2_FLAG) {
  *(uint16_t*)&TIM2->SR1 &= ~(TIM2_FLAG);
}

FlagStatus TIM2_GetFlagStatus(TIM2_FLAG_TypeDef TIM2_FLAG) {
  return (*(uint16_t*)&TIM2->SR1 & TIM2_FLAG) ? SET : RESET;
}
Сравните с оригиналом и почувствуйте, что называется, разницу.

Re: Программирование STM8

Добавлено: Сб дек 10, 2016 18:42:29
GARMIN
Дико плюсую по программистскому подходу.
Однако, добавлю от себя по логике работы: зачем городить функции, когда можно просто глянуть нужный флаг в регистре таймера?
В моём случае, когда код инициализации uart превысил 2 килобайта, я отказался от SPL (правда, это было на STM32F051). С тех пор достаточно регистров, и не жалею.
Причём и на STM8S, и на STM32F446.

Re: Программирование STM8

Добавлено: Сб дек 10, 2016 18:52:52
scorpi_0n
GARMIN писал(а):я отказался от SPL (правда, это было на STM32F051). С тех пор достаточно регистров, и не жалею.
Причём и на STM8S, и на STM32F446.
Согласен! Пусть попробуют при плотном коде работы с периферией покрутиться с этими жирными функциями, хоть в первой редакции, хоть во второй. Про прерывания вообще страшно подумать.

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 00:06:28
a5021
GARMIN писал(а):Однако, добавлю от себя по логике работы: зачем городить функции, когда можно просто глянуть нужный флаг в регистре таймера?
На вопрос "зачем", можно даже попробовать найти непротиворечивый ответ, но на то, чем за это придется платить, я предлагаю все-таки взглянуть. Речь о исполняемом коде, который получается после компиляции.

Чтобы не умножать печалей, я возьму уже причесанные функции из моего предыдущего сообщения и сравню, насколько отличается гененрируемый компилятором код, если проверять статус таймера посредством вызова функций и посредством прямого обращения к регистрам.

Простой пример:

Код: Выделить всё

  if (TIM2_GetFlagStatus(TIM2_FLAG_CC1) == SET) {
    TIM2_ClearFlag(TIM2_FLAG_CC1);
  }

  if (TIM2->SR1 & TIM2_SR1_CC2IF) {
    TIM2->SR1 &= ~TIM2_SR1_CC2IF;
  }
В первой проверке условия используется вызов функций, во второй обращение к регистрам. При включенной по максимуму оптимизации компилятор выдал следующий код:

Код: Выделить всё

  42            if (TIM2_GetFlagStatus(TIM2_FLAG_CC1) == SET) {
\                     ??main_0:
\   00001F CE 5304      LDW       X, L:0x5304                 ; 2, 3
\   000022 9093         LDW       Y, X                        ; 1, 2
\   000024 02           RLWA      X, A                        ; 1, 1
\   000025 A4 02        AND       A, #0x2                     ; 1, 2
\   000027 02           RLWA      X, A                        ; 1, 1
\   000028 4F           CLR       A                           ; 1, 1
\   000029 02           RLWA      X, A                        ; 1, 1
\   00002A 51           EXGW      X, Y                        ; 1, 1
\   00002B 905D         TNZW      Y                           ; 2, 2
\   00002D 27 07        JREQ      L:??main_1                  ; 1, 2
  43              TIM2_ClearFlag(TIM2_FLAG_CC1);              
\   00002F 02           RLWA      X, A                        ; 1, 1
\   000030 A4 FD        AND       A, #0xfd                    ; 1, 2
\   000032 01           RRWA      X, A                        ; 1, 1
\   000033 CF 5304      LDW       L:0x5304, X                 ; 2, 3
  44            }                                             ;==========
  45                                                          ; 17, 23
  46            if (TIM2->SR1 & TIM2_SR1_CC2IF) {
\                     ??main_1:
\   000036 7205 5304 04 BTJF      L:0x5304, #0x2, L:??main_2  ; 2, 5
  47              TIM2->SR1 &= ~TIM2_SR1_CC2IF;
\   00003B 7215 5304    BRES      L:0x5304, #0x2              ; 1, 4
  48            }                                             ;==========
                                                              ; 3, 9
Соптимизировалось все, стоит заметить, довольно неплохо. Функции заинлайнились и код вышел вполне компактным. Для каждой строчки я посчитал время выполнения и объем (две цифры в комментариях), которые ниже просуммировал. Итого, при использовании функций для проверки и сброса флага потребуется выполнить 14 команд, по времени это займет 17 тактов процессора и расход флеша составит 23 байта.
Точно такое же действие, выполненное через обращения к регистрам, потребует выполнения двух команд, трех тактов процессора и девяти байт флеша. Выигрыш по размеру кода около трех раз, по скорости почти шесть. Цифры говорят сами за себя и комментировать тут больше нечего.

Еще хотелось бы заметить вот что: SPL вызывает грустные чувства не только тем, что код написан безобразно, безобразен так же и дизайн библиотеки. Вот прямо по этим двум функциям можно предъявлять претензии. Причем, не по тому, как они написаны, а относительно того, что они вообще делают. Ну нафиг ведь не сдалось проверять или сбрасывать оба статусных регистра таймера вместе. SR2 хранит флаги относящиеся только к режиму захвата (причем, для отображения редкой ситуации т.н. перезахвата). В остальных режимах (а их большинство и используются они много чаще) данный регистр в принципе не может содержать полезной информации и/или использоваться осмысленно. Но какая-то светлая индусская голова решила, что "нужно трясти" и вот с тех пор оно трясется безостановочно и совершенно безо всякого смысла.

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 00:23:52
Chettuser
У меня вообще ощущение, что STM8 производитель забросил на самотёк и больше не планирует поддерживать, а зря - в определённой нише даже 32F030 жирновато будет, ИМХО.

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 11:34:23
ptr128
a5021 писал(а):писанину обдолбанных индусов ... молиться на нее, как на сокровищницу программистской мысли?
социализации больных с тяжелыми формами аутизма ... чтобы у больных ... эту долбанину исключительно сложно.
Я уже как-то писал, что подобный лексикон заставляет мое воображение услужливо рисовать склочную бабу, не способную вообще ни к какому виду общения без эмоционального накала и перехода на личности (пусть даже личности авторов SPL) :)))
Если считаете себя специалистом, так ведите себя соответствующе.
a5021 писал(а):Любопытства ради, я просмотрел сейчас код
Ну раз ST предлагает эту библиотеку в качестве эталона и другой библиотеки я на просторах инета не встречал, то вариантов у нас не много:
1. Использовать ее непосредственно
2. Использовать ее в виде документации, но программируя самостоятельно
3. Не использовать ее вообще, руководствуюясь только datasheet

Я склоняюсь, ко второму варинту, о чем уже писал выше:
ptr писал(а):А как по мне, такие вещи вообще правильней макросами делать без лишних функций.
Поэтому оптимальность и красота кода в ней мне глубоко монопенисуальна. А вот явные баги - нет. Поэтому про багу я и написал.
А все что изложили Вы вообще ни на что не виляет, так как все эти лишние преобразования типа и присвоения на результирующий код не повлияют, благодаря оптимизатору.
a5021 писал(а):Сравните с оригиналом и почувствуйте, что называется, разницу.
Если Вы склоняетесь к первому варинту использования этой библиотеки, то IMHO, Вы сильно не правы. Вне зависимости от качества кода SPL, при наличии всего трех регистров общего назначения, они, в случае функции, любым компилятором буду гоняться в стек и обратно. Очень не эффективно и с точки зрения производительности, и с точки зрения расхода памяти.
Если ко второму, как и я, смысл Ваших исследований - нулевой.
Если Вы склоняетесь к третьему варианту, то зачем Вы тогда вообще в эту библиотеку полезли? Времени лишнего что ли навалом? :)))

Убедительная просьба, о багах в SPL здесь писать, потому что не всякий новичок их сразу заметит. О качестве кода - не стоит. Так можно всю ветку загадить не принеся ни йоты толку. А эмоциональные оценки оставьте, пожалуйста для склочных баб или, хотя бы, для сайтов знакомств :)))

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 15:16:00
scorpi_0n
ptr128 писал(а): Убедительная просьба, о багах в SPL здесь писать, потому что не всякий новичок их сразу заметит. О качестве кода - не стоит. Так можно всю ветку загадить не принеся ни йоты толку.
В этом нет никаго смысла. Ибо SPL сама по себе один большой баг и предназначена она лишь для знакомства с СТМ8, а не для полноценной работы с ней. Это типа придаток к демокоду. Да и тема здесь не про SPL, а про СТМ8 вообще, если вы ещё не заметили.

Добавлено after 9 minutes 42 seconds:
Chettuser писал(а):У меня вообще ощущение, что STM8 производитель забросил на самотёк и больше не планирует поддерживать, а зря - в определённой нише даже 32F030 жирновато будет, ИМХО.
STM8 это как бы улучшение ST7. И этим всё сказано. СТМ как бы и не скрывает, что в приоритете СТМ32, а схожесть периферии заложили специально, чтобы можно было переходить с СТМ8 на СТМ32 и с СТМ32 на СТМ8 в случае необходимости. Поэтому СТМ8 и выглядит как придаток к СТМ32 для самых мелких решений.

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 17:04:31
ptr128
ptr128 писал(а): Файл stm8s_tim2.c, функция TIM2_ClearFlag, строка 1110:

Код: Выделить всё

TIM2->SR2 = (uint8_t)(~((uint8_t)((uint8_t)TIM2_FLAG >> 8)));
У меня устойчивое ощущение, что должно быть:

Код: Выделить всё

TIM2->SR2 = (uint8_t)(~((uint8_t)(TIM2_FLAG >> 8)));
Так как scorpi_0n понизил рейтинг моего сообщения, делаю вывод, что он считает, что тут в SPL баги нет.
Кто тоже так считает - присоединяйтесь :)))

a5021 присоединился. Есть еще кто, столь же уверенный, что это не бага в SPL? :)))

Re: Программирование STM8

Добавлено: Вс дек 11, 2016 20:38:39
Chettuser
Ткните носом в документ с описанием регистров STM8? После CMSIS STM32 как то нет желания возвращаться к SPL.