41 Востаннє редагувалося taburyak (25.07.2016 18:17:27)

Re: STM32, Atolic TrueStudio, CubeMX

Прихований текст

Малечі вже 1.5 рочки і іноді вона може сама погратись 15-20 хвилин і в мене іноді є можливість приділити час захопленню

Є такий шмат коду:

//Функція відображення інформації на індикатор
void ShowScreen(uint8_t* number, uint8_t number_of_digits)
{
    uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin};
    for(int i = 0; i < number_of_digits; i++)
    {
        IND_PORT -> BRR = (D0_Pin|D1_Pin|D2_Pin|D3_Pin);//Вимикаємо всі розряди
        IND_PORT -> BSRR = digitPin[i];//Вмикаємо потрібний розряд індикатора
        DigitToPort(*(number+i));//Виводимо цифру у потрібний розряд
        HAL_Delay(1);//Невеличка затримка. Хай цифра світиться якийсь час
    }
}

Де number це одномірний масив з однорозрядними цифрами.
Чув що за глобальні змінні розстріл чи там 15 років з конфіскацією :)
Тому в функцію передається вказівник на масив і кількість елементів масиву.
Це все чудово працює. Але є маленьке питання. В рядку 4 оголошую масив, де перераховую дефайни які містять відповідні регистри. А потім зручно в циклі підсовувати змінну "i" замість "D0_Pin...D3_Pin", щоб не копіпастити код. Тепер питання, а чи це нормальний спосіб? Чи може є більш елегантніший/професійний спосіб? Чи взагалі якісь варіанти є?

Тепер глобальне питання!
Створив структуру:

typedef struct
{
    int current;
    int previous;
    bool flag_visible;
}CounterTypeDef;

Потім оголосив і ініціалізував масив з структур:

CounterTypeDef AI_Counter[16] = {}; // Масив з 16 структур для лічильників

І з-за того що оголосив масив структур в глобальних змінних, то теж все працює, маю доступ до елементів масиву структур звідусіль таким чином:

AI_Counter[0].current = 19990;
  AI_Counter[0].previous = 0;
  AI_Counter[0].flag_visible = false;

Але ж хочеться позбавитись глобальних змінних. Передати функції вказівник на масив структур виходить, так як і на звичайний масив:

void anyFunc(CounterTypeDef* AI_Counter);

Але як далі в функції обробляти? Я не розумію. Як би поодинока структура, то зрозуміло.
Наприклад там:

AI_Counter->current++;

Але це ж масив структур. Треба якось вказати не тільки елемент структури, а і елемент масиву структур. І я не знаю як з цим впоратись. По пошуку нічого підходящого не знаходжу.
Допоможіть.

42

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
void anyFunc(CounterTypeDef* AI_Counter);

Але як далі в функції обробляти? Я не розумію. Як би поодинока структура, то зрозуміло.
Наприклад там:

AI_Counter->current++;

Але це ж масив структур. Треба якось вказати не тільки елемент структури, а і елемент масиву структур. І я не знаю як з цим впоратись.

Якось так:

AI_Counter[i].current++;
(AI_Counter + i)->current++;
(*(AI_Counter + i)).current++;
(&(AI_Counter[i]))->current++;
Подякували: taburyak1

43

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
Прихований текст

Малечі вже 1.5 рочки і іноді вона може сама погратись 15-20 хвилин і в мене іноді є можливість приділити час захопленню

Є такий шмат коду:

//Функція відображення інформації на індикатор
void ShowScreen(uint8_t* number, uint8_t number_of_digits)
{
    uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin};
    for(int i = 0; i < number_of_digits; i++)
    {
        IND_PORT -> BRR = (D0_Pin|D1_Pin|D2_Pin|D3_Pin);//Вимикаємо всі розряди
        IND_PORT -> BSRR = digitPin[i];//Вмикаємо потрібний розряд індикатора
        DigitToPort(*(number+i));//Виводимо цифру у потрібний розряд
        HAL_Delay(1);//Невеличка затримка. Хай цифра світиться якийсь час
    }
}

...

Я б написав так

 const uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin};

і зберіг 8 байт в RAM. і не побоявся б навіть винести за межі функції.

Сильно мерехтить індикація?

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

44

Re: STM32, Atolic TrueStudio, CubeMX

VitekSVM написав:

Я б написав так

 const uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin};

і зберіг 8 байт в RAM. і не побоявся б навіть винести за межі функції.

Сильно мерехтить індикація?

Дякую. Де можливо поставив const. Але розмір програми не змінився. Чи мається на увазі економія ОЗП, бо const зберігається у флеші?

За межі не виніс масив, бо функція викликає функцію і як передати масив, аж туди, я поки не можу второпати.

Не мерехтить, бо коду не багато і затримок немає.

45 Востаннє редагувалося ReAl (28.07.2016 23:53:13)

Re: STM32, Atolic TrueStudio, CubeMX

VitekSVM написав:

Я б написав так

 const uint16_t digitPin[] = {D0_Pin,D1_Pin,D2_Pin,D3_Pin};

і зберіг 8 байт в RAM. і не побоявся б навіть винести за межі функції.

Не «не побоявся б», а «обов'язково», інакше різниці з варіантом без const не буде взагалі.

Принаймні, в межах стандарту у тілі функції це буде зроблено константну автоматичну змінну, яка розміщена на стекові, а не деінде. Різниця з варіантом без const лише в тому, що компілятор не дасть її поміняти (також може уоптимізувати звернення з константним індексом, тобто digiPin[1] відразу дасть потрібну константу, а не лізтиме у масив). А так — і те і те на стекові, і те і те ініціалізується там у момент виклику функції копіюванням образу з секції .rodata.

Але речі, потрібні лише одній функції, краще в ній і описувати, не виносити у глобальні. А щоб розмістило не на стекові і не ініціалізувало кожен раз, треба дати static const. За виключенням області видимості це буде те ж саме, що просто const за межами функції, масив так і буде у секції .rodata, зекономиться як глибина стеку, так і код (мінус копіювання flash -> RAM).
Порівняйте (скрізь arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -O2, версія 4.9.3):

int foo(int i)
{
    int  d[] = {0,1,2,3};
    return d[i&0x03];
}

foo:
    push    {r4, lr}
    ldr    r3, .L3  // адреса образу в .rodata
    sub    sp, sp, #16  // резерв місця під локальний масив
    add    lr, sp, #16
    and    r4, r0, #3
    ldmia    r3, {r0, r1, r2, r3}  // ініціалізація масиву
    stmdb    lr, {r0, r1, r2, r3}
    add    r4, lr, r4, lsl #2    // звертання до локального масиву
    ldr    r0, [r4, #-16]
    add    sp, sp, #16
    @ sp needed
    pop    {r4, pc}
.L4:
    .align    2
.L3:
    .word    .LANCHOR0
    .size    foo, .-foo
    .section    .rodata
    .align    2
    .set    .LANCHOR0,. + 0
.LC0:
    .word    0
    .word    1
    .word    2
    .word    3

тепер зі словом const — «знайдіть відмінноcті» ;-)

int moo(int i)
{
    const int d[] = {10,11,12,13};
    return d[i&0x03];
}
moo:
    push    {r4, lr}
    ldr    r3, .L3
    sub    sp, sp, #16
    add    lr, sp, #16
    and    r4, r0, #3
    ldmia    r3, {r0, r1, r2, r3}
    stmdb    lr, {r0, r1, r2, r3}
    add    r4, lr, r4, lsl #2
    ldr    r0, [r4, #-16]
    add    sp, sp, #16
    pop    {r4, pc}
.L4:
    .align    2
.L3:
    .word    .LANCHOR0
    .size    moo, .-moo
    .section    .rodata
    .align    2
    .set    .LANCHOR0,. + 0
.LC0:
    .word    10
    .word    11
    .word    12
    .word    13

А от тепер static const

int kwa(int i)
{
    static const int d[] = {20,21,22,23};
    return d[i&0x03];
}
kwa:
    ldr    r3, .L2
    and    r0, r0, #3
    ldr    r0, [r3, r0, lsl #2]
    bx    lr
.L3:
    .align    2
.L2:
    .word    .LANCHOR0
    .size    kwa, .-kwa
    .section    .rodata
    .align    2
    .set    .LANCHOR0,. + 0
    .type    d.4078, %object
    .size    d.4078, 16
d.4078:
    .word    20
    .word    21
    .word    22
    .word    23

До речі, просто static (або винесення за межі функції) було б з точки зору розміру коду краще, ніж просто const без винесення за межі функції, бо масив ініціалізувався б один раз при старті програми разом з усією секцією .data.

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

46

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

До речі, просто static (або винесення за межі функції) було б з точки зору розміру коду краще, ніж просто const без винесення за межі функції, бо масив ініціалізувався б один раз при старті програми разом з усією секцією .data.

Велике дякую.

Дослухався вашої поради. Виніс масив за межі функції та додав static ще декільком масивам. Таки на виході код став значно меншим.

47

Re: STM32, Atolic TrueStudio, CubeMX

Про const теж не забувайте :-)
Якщо на щось можна навісити const, це варто зробити. Десь вбереже від набажаної зміни, десь додасть простору для роботи оптимізатора.

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

48

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Про const теж не забувайте :-)

Не забув. Також дописав до своїх функцій static і увімкнув оптимізацію по розміру. З 27 кілобайтів зменшилось до 18 кілобайт. Цікавенько.

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

49

Re: STM32, Atolic TrueStudio, CubeMX

Хтось може мені допомогти? Бо я мабуть чогось не розумію.
Так як CooCox скоріше мертвий чим живий, став пробувати інші засоби розробки такі як System Workbench for STM32 та TRUE Studio проблема одна й та ж. Ні debugger ні RUN не працюють.

Наприклад в System Workbench

Помилка дебагера:

"Error in final launch sequence
Failed to execute MI command:
-target-select remote localhost:3333

Error message from debugger back end:
localhost:3333: The system tried to join a drive to a directory on a joined drive.
localhost:3333: The system tried to join a drive to a directory on a joined drive."

Помилка RUN:

"Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 2000 kHz
adapter_nsrst_delay: 100
srst_only separate srst_nogate srst_open_drain connect_assert_srst
srst_only separate srst_nogate srst_open_drain connect_assert_srst
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : clock speed 1800 kHz
Error: open failed
in procedure 'program'
in procedure 'init' called at file "embedded:startup.tcl", line 473
in procedure 'ocd_bouncer'
** OpenOCD init failed **
shutdown command invoked"

Підозрюю що треба налаштувати щось там, але я не знаю що. Гугл не помагає в цьому. В CooCox все просто build, debagg, flash. А тут build тільки працює і заливаю прошивку через сторонній прошивач. ST-LINK utility.

System WorkBench і TRUE Studio основані на ECLIPSE і між собою схожі. Думаю проблема одна й та ж. Треба якось налаштувати правильно. А як?

50 Востаннє редагувалося taburyak (01.09.2016 21:15:01)

Re: STM32, Atolic TrueStudio, CubeMX

Вітання.
Прошу допомоги. Самотужки не можу зрозуміти як це реалізувати.
Переробляю бібліотеку для екранчику WH1602 чи HD44780. Все працює чудово. Але хотів автоматизувати налаштування потрібних виводів. Зараз треба в ручну вводити номера пінів на яких висить екранчик. А хочу щоб номер піна брався автоматом з іншого місця. З портами на яких сидять піни вийшло, а от з самими пінами не знаю як.

Ось як зараз у файлі lcd_cfg.h який входить до складу бібліотеки hd44780:

#define LCD_E_OUT                    LCD_E_GPIO_Port->ODR    /* Output register */
#define LCD_E                          1u    /* Pin number */

#define LCD_RS_OUT                    LCD_RS_GPIO_Port->ODR    /* Output register */
#define LCD_RS                         0u    /* Pin number */

#define LCD_RW_OUT                    LCD_RW_GPIO_Port->ODR    /* Output register */
#define LCD_RW                        3u    /* Pin number */

#define LCD_D7_OUT                    LCD_D7_GPIO_Port->ODR    /* Output register */
#define LCD_D7_IN                    LCD_D7_GPIO_Port->IDR    /* Input register */
#define LCD_D7                          7u    /* Pin number */

#define LCD_D6_OUT                    LCD_D6_GPIO_Port->ODR    /* Output register */
#define LCD_D6                        6u    /* Pin number */

#define LCD_D5_OUT                    LCD_D5_GPIO_Port->ODR    /* Output register */
#define LCD_D5                        1u    /* Pin number */

#define LCD_D4_OUT                    LCD_D4_GPIO_Port->ODR    /* Output register */
#define LCD_D4                        0u    /* Pin number */

Як переробити щоб потрібний "Pin number" підставлявся з ряду чисел (0u - 15u) в залежності що є в файлі mxconstans.h який генерує CubeMX:

#define LCD_RS_Pin GPIO_PIN_0
#define LCD_RS_GPIO_Port GPIOC
#define LCD_E_Pin GPIO_PIN_1
#define LCD_E_GPIO_Port GPIOC
#define USER_BUTTON_Pin GPIO_PIN_0
#define USER_BUTTON_GPIO_Port GPIOA
#define LCD_D4_Pin GPIO_PIN_0
#define LCD_D4_GPIO_Port GPIOB
#define LCD_D5_Pin GPIO_PIN_1
#define LCD_D5_GPIO_Port GPIOB
#define LCD_D6_Pin GPIO_PIN_6
#define LCD_D6_GPIO_Port GPIOC
#define LCD_D7_Pin GPIO_PIN_7
#define LCD_D7_GPIO_Port GPIOC
#define LED_BLUE_Pin GPIO_PIN_8
#define LED_BLUE_GPIO_Port GPIOC
#define LED_GREEN_Pin GPIO_PIN_9
#define LED_GREEN_GPIO_Port GPIOC

Наприклад в mxconstants.h визначено що LCD_RS_Pin це GPIO_PIN_0, то в файлі lcd_cfg.h має якось зазначатись що LCD_RS це 0u. Якщо LCD_RS_Pin це GPIO_PIN_1, то LCD_RS це 1u і так далі. Файл mxconstants.h генерує CubeMX, а файл lcd_cfg.h можна правити на свій розсуд.

Ну ще в додачу як визначені константи в hal_gpio.h . Може допоможе

/** @defgroup GPIO_pins_define GPIO pins define
  * @{
  */ 
#define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */
#define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */
#define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */
#define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */
#define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
#define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */
#define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */
#define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */
#define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */
#define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */
#define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */
#define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */
#define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */
#define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */
#define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */
#define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */
#define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */

51

Re: STM32, Atolic TrueStudio, CubeMX

Якщо LCD_RS_Pin це GPIO_PIN_1, то LCD_RS це 1u і так далі.

Напишіть файл крос-дефайнів, наприклад:

#define LCD_RS            LCD_RS_Pin
... і так далі

це дає можливість взяти за LCD_RS те, що береться для LCD_RS_Pin.

Подякували: 0xDADA11C71

52 Востаннє редагувалося taburyak (02.09.2016 10:02:09)

Re: STM32, Atolic TrueStudio, CubeMX

Тоді це буде ((uint16_t)0x0002), а не 1u. Не те пальто.

53 Востаннє редагувалося voland (02.09.2016 10:47:21)

Re: STM32, Atolic TrueStudio, CubeMX

...буде незручно, але скористуйтеся макросом:

#define MASK2PIN(mask) ((mask&0001)?0:(mask&0x0002)?1:(mask&0x0004)?2:(mask&0x0008)?3: \
  (mask&0x0010)?4:(mask&0x0020)?5:(mask&0x0040)?6:(mask&0x0080)?7: \
  (mask&0x0100)?8:(mask&0x0200)?9:(mask&0x0400)?10:(mask&0x0800)?11: \
  (mask&0x1000)?12:(mask&0x2000)?13:(mask&0x4000)?14:(mask&0x8000)?15:0)

Таким чином, потім треба додати:

#define RS_PIN_NUMBER (MASK2PIN(RS_PIN)) 
Подякували: taburyak, 0xDADA11C7, leofun013

54 Востаннє редагувалося taburyak (02.09.2016 18:28:13)

Re: STM32, Atolic TrueStudio, CubeMX

Велике дякую!  *BRAVO* Це неймовірно!  *THUMBSUP* Я б так не зміг  *DONT_KNOW*

voland написав:

...буде незручно, але скористуйтеся макросом:

А в чому незручності? Вже туди і заглядати не треба, все автоматично.

Зробив так, щоб було більш абстрактно:

#define MASK2PIN(mask) ((mask&GPIO_PIN_0)?0:(mask&GPIO_PIN_1)?1:(mask&GPIO_PIN_2)?2:(mask&GPIO_PIN_3)?3: \
                        (mask&GPIO_PIN_4)?4:(mask&GPIO_PIN_5)?5:(mask&GPIO_PIN_6)?6:(mask&GPIO_PIN_7)?7: \
                        (mask&GPIO_PIN_8)?8:(mask&GPIO_PIN_9)?9:(mask&GPIO_PIN_10)?10:(mask&GPIO_PIN_11)?11: \
                        (mask&GPIO_PIN_12)?12:(mask&GPIO_PIN_13)?13:(mask&GPIO_PIN_14)?14:(mask&GPIO_PIN_15)?15:0)

#define RS_PIN_NUMBER (MASK2PIN(LCD_RS_Pin))
#define E_PIN_NUMBER (MASK2PIN(LCD_E_Pin))
#define RW_PIN_NUMBER (MASK2PIN(LCD_RW_Pin))
#define D7_PIN_NUMBER (MASK2PIN(LCD_D7_Pin))
#define D6_PIN_NUMBER (MASK2PIN(LCD_D6_Pin))
#define D5_PIN_NUMBER (MASK2PIN(LCD_D5_Pin))
#define D4_PIN_NUMBER (MASK2PIN(LCD_D4_Pin))
Подякували: 0xDADA11C71

55

Re: STM32, Atolic TrueStudio, CubeMX

А в чому незручності? Вже туди і заглядати не треба, все автоматично.
Зробив так, щоб було більш абстрактно

Ну так навіть краще ).
Незручності в тому, що цей макрос перетворює одне число в друге тільки у випадку оптимізації. Тобто оптимізатор бачить, що ваша "D5_PIN_NUMBER" залежить лише від констант і перетворює низку поривнянь и масок до одної константи. А якщо ви із якоїсь причини відключите оптимізацію - компілятор завжди буде втикать 16 масок и 16 порівнянь кожен раз, для кожної дії з бітами. Хоча, можливо, він цього и не зробить - я точно не знаю. Різні компілятори діють по-різному. Але я зустрічав такі випадки, коли код був просто геть скаженим після компіляції. Наприклад, GCC може вертати з функції 16-бітне число в регістрах, навіть якщо функція має 8-мибітне зворотнє значення. І навіть у випадку використання inline-асемблера.

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

56

Re: STM32, Atolic TrueStudio, CubeMX

voland написав:

Різні компілятори діють по-різному.

Ще раз дякую. Буду мати на увазі. Пограюсь з різними компіляторами і опціями оптимізації. Побачу що до чого.

57 Востаннє редагувалося taburyak (05.10.2016 16:13:00)

Re: STM32, Atolic TrueStudio, CubeMX

Вітання.
Зробив лічильник подій 4х4, всього 16. Подія фіксується контактами реле. Через оптрон на мікроконтролер. Спочатку схема оптопари була як на схемі ліворуч. Іноді один лічильник ловив хибне спрацювання. За добу 10 -20 похибок. Можливо ще один лічильник давав близько 1 похибки на добу.
Щоб виправити ситуацію, додав до схем RC фільтр, схема що праворуч, щоб навіяне в дротах на землю гасив. Стало ще гірше. Тепер вже 4 лічильники з 16 ловлять хибні спрацювання, які рахуються десятками за годину. Як так? Покращив схему, а стало гірше?
https://lh3.googleusercontent.com/AklxbpZWm-Bse0eGJrZbxuULheJ2-OFS_1VhLwQAb0z95AoI4Z19HB128E5moWfqjSaLjb8BXjRX51p7_pDx2F2V-0g0EyoUgkNnYvVdottbBYBHSkkXFrZW2Twsjejy7UbrCsCd0mxzj127WrBjcV7ogEBv3pI9lI9KWbBCY3cWh0WwICe0vgsI4f55US7fujRGWLUIxNvmTpVh1vp6RPW3qtbDDxgrL4M_u-IOzG2WnRi1zmd6n7SnL8iR2FyqdAMcdOGr3zOF5mPURBzvzf3Z7wOvvH8AmakW7e-tK2bxN183amTQryNkmSLb57f6SVNRM_wBjbwLGaT0r3P-lgM0YgIafsoL-ii-gYPNIzK7Jf78rq0C7oHpy5-xE79iOX_b2CC0aCES87aThblxWQHoMXAei29C7NcaWFAQ844oEwq8i0_CsYGRZWOM-ENQ94Kg3HRMJLdLajZ7Qt-KybxtqO_nUbyiuyyzVTciEkFPRcUoPbWQmeXX8Mxlf3CYB6CqxlOpt0qxsjp-9Dl5BF8nJ1kkbVhPkbl9M77YhIS2W-xHgCD2J9wHoISKvaAwi4SP0ogMn70bjwhzJ8W7QNC5kHwd2Xvd4hzjsmjU_BzLZg-WQA=w1353-h638-no
На схемі К.Р. - контакти реле. МК - ніжка мікроконтролеру.
Є якісь думки, поради? Програмний антибрязкіт є. Опитуються всі лічильники і виставляється заборона на подальше опитування. Через 50 мілісекунд виставляється дозвіл на опитування. Між було і стало в схемі - програма не мінялась.

58

Re: STM32, Atolic TrueStudio, CubeMX

...немає ні схеми, ні коду. Як вы хочете, щоб вам допомогли?

59

Re: STM32, Atolic TrueStudio, CubeMX

Схема ж є! Зразу приліпив. Не видно? А код ні при чому.
Та й вже сам розібрався. Збільшив номінал опору на світлодіоді оптичної пари. Типу збільшив поріг спрацювання. Все нормально.

Хто може буде оновлювати STMCubeMX до 4.17.0 є підводна каменюка http://stm32withoutfear.blogspot.com/20 … -4170.html

60

Re: STM32, Atolic TrueStudio, CubeMX

Колись давно шановний VitekSVM, свого часу, дуже допоміг з цим меню розібратись, хоч на той час в мене так і не вийшло.

VitekSVM написав:
#define MENU_ITEM_READ_POINTER(Addr)   (void*)pgm_read_word(Addr)

замінити на

#define MENU_ITEM_READ_POINTER(Addr)   (void*)(Addr)

І ось знову дійшло діло і до micromenu-2 https://github.com/abcminiuser/micromenu-v2.

Воно для AVR, але для STM32 теж підходить, прибрати PROGMEM і все таке. Вже на другій сторінці топіку розібрались. Ну то деталі. А питання в іншому.

Ось при такому запису, як запропонував VitekSVM:

#define MENU_ITEM_READ_POINTER(Addr)   (void*)(Addr)

Зависає мікроконтролер в цьому місці:

void (*SelectCallback)(void) = MENU_ITEM_READ_POINTER(&CurrentMenuItem->SelectCallback);

    if (SelectCallback)
        SelectCallback();

А саме на останньому рядку SelectCallback();

При такому запису:

#define MENU_ITEM_READ_POINTER(Addr)   *(Addr)

Запрацювало. І я дуже зрадів. Але ж цікаво чому.

Хтось в курсі чому так відбувається? Ну або чим запис (void*)(Addr) відрізняється від *(Addr)?