Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AVR Toolchain - как работать с __flash?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
ARV
Не едут лыжи, помогите понять, почему происходит следующее.

есть такая структура
Код
typedef struct{
    uint8_t        prev_ch;            // предыдущий символ
    uint8_t        curr_ch;            // текущий символ
    uint8_t        auto_eq;            // автовставка TOC_EQUAL
    uint8_t        can_ok;                // разрешено нажатие ОК (конец редактирования)
    uint8_t        approved_begin;        // индекс первого разрешенного следующего символа
    uint8_t        approved_end;        // индекс последнего разрешенного следующего символа
} smart_rule;
делаю массив таких структур в адресном пространстве __flash, которое как бы поддерживается AVR Toolchain (и для обычных строк действительно поддерживается!)
Код
const smart_rule __flash rules[RULES_CNT] = { тут инициализирую все структуры }

затем есть код, с которым дикие проблемы:
Код
uint8_t find_rule(uint8_t pos, char *s){
    uint8_t i;

    for(i=0; i < RULES_CNT; i++){
        if((rules[i].prev_ch == NO_CHAR) && (pos == 0)){
            if((rules[i].curr_ch == NO_CHAR) && (s[pos] == ' ')) break;
            if((rules[i].curr_ch == ANY_VAR) && (s[pos] >= TOC_WDAY) && (s[pos] <= TOC_QUART)) break;
            if(rules[i].curr_ch == s[pos]) break;
        }
        if(rules[i].prev_ch == ANY_CHAR){
            if((rules[i].curr_ch == NO_CHAR) && (s[pos] == ' ')) break;
            if((rules[i].curr_ch == ANY_VAR) && (s[pos] >= TOC_WDAY) && (s[pos] <= TOC_QUART)) break;
            if(rules[i].curr_ch == s[pos]) break;
        }
        if((rules[i].prev_ch == ANY_DIG) && (s[pos-1] >= '0') && (s[pos-1] <= '9')){
            if((rules[i].curr_ch == NO_CHAR) && (s[pos] == ' ')) break;
            if((rules[i].curr_ch == ANY_DIG) && (s[pos-1] >= '0') && (s[pos-1] <= '9')) break;
            if((rules[i].curr_ch == ANY_VAR) && (s[pos] >= TOC_WDAY) && (s[pos] <= TOC_QUART)) break;
            if(rules[i].curr_ch == s[pos]) break;
        }
    }
    return i;
}
проблемы следующие:
1. в том виде, как описано, Eclipse категорически отказывается понимать обращение к массиву типа такого rules[i].prev_ch - пишет, что Field 'prev_ch' could not be resolved, аналогично и на все другие поля. при этом компиляция идет без ошибок.
2. Eclipse перестает ругаться, если меняю определение массива на такое: __flash const smart_rule rules[RULES_CNT]
3. ладно, пусть я не понимаю, как правильно определить массив во flash, НО!!!! в итоговом коде нет тела вышеприведенной функции find_rule - если отключаю оптимизацию, остается ПУСТОЙ ЦИКЛ, а при включенной оптимизации даже нет обращения к функции!

ПОЧЕМУ?
почему компилятор считает, что ни один if не сработает? что я делаю не так? почему если я задаю опции -fdata-sections и -Wl,-gc-sections, то мой массив rules исчезает из кода?! я же делаю к нему обращения!
smalcom
AVR имеет девственную гарвардскую архитектуру. Для чтения данных из памяти программ используется набор ф-й pgm_read_xxx.
Посмотрите примерчики avrlib и макрос PGM_P.
Сергей Борщ
Цитата(smalcom @ Mar 1 2015, 22:54) *
Для чтения данных из памяти программ используется набор ф-й pgm_read_xxx.
Вы отстали от жизни. Уже довольно давно в avr-gcc в режиме C зявлена поддержка различных адресных пространств и квалификатор __flash.
smalcom
https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html

действительно отстал))
ARV
я перешел с WinAVR на AVR Toolchain практически только из-за этой самой поддержки __flash, ибо реализация вышеупомянутой функции при помощи pgm_read_xxxx - это не геморрой даже, это ужас нерожденного...

так что по существу моего вопроса скажете, уважаемые коллеги? неужели никто с массивами структур во flash не работает?!
Сергей Борщ
Увы, не использую эти квалификаторы. Когда только появлялась поддержка этого квалификатора, ее автор писал что не будет добавлять ее в режиме С++, потому что он не использует плюсы и вообще адресные пространства добавлены только в стандарт С, но не в С++. А поскольку я пишу только на С++ - приходится по старинке, pgm_read_xxx(). Пользуюсь компилятором из репозитория убунты. Под виндовсом после смерти WinAVR использовал сборки отсюда.
ARV
pgm_read_xxx - это кошмар sad.gif проще будет перенести массив в ОЗУ.

перенес массив в ОЗУ... складывается впечатление, что что-то у меня не то записано в условиях внутри цикла, потому что компилятор упорно выбрасывает все if-ы - видно, считает, что условия никогда не выполняются. но я не вижу этой однозначности... может, со стороны виднее: ткните носом!
Сергей Борщ
Так с наскока тоже не вижу. А чему равны константы ANY_CHAR, NO_CHAR, ANY_DIG, ANY_VAR?
ARV
Код
#define NO_CHAR        -1
#define ANY_VAR        -2
#define ANY_DIG        -3
#define ANY_CHAR    -4

в массиве - набор правил, т.е. условий проверки пары символов в строке. должны совпасть оба символа в строке с тем, что задано в одной из структур массива. если задано prev_ch = NO_CHAR - предыдущий символ не проверяется, потому что это ситуация начала строки и предыдущего символа просто нет. если curr_ch = NO_CHAR - в строке должен быть на текущей позиции пробел. ANY_VAR - символ в строке должен лежать в некоем диапазоне значений. ANY_DIG - символ должен быть цифрой. все остальное - прямое равенство. номер структуры, для которой первой все условия совпадут и есть номер правила.
demiurg_spb
Цитата(ARV @ Mar 2 2015, 11:58) *
Какую версию компилятора используете?

http://sourceforge.net/projects/mobileches...hots%20(Win32)/
- c этим (avr-gcc-4.9.2 (prerelease)) тулчейном у меня всё отлично работает.
Во всю использую __flash...
Сергей Борщ
Цитата(ARV @ Mar 2 2015, 10:58) *
Код
#define NO_CHAR        -1
#define ANY_VAR        -2
#define ANY_DIG        -3
#define ANY_CHAR    -4
Тогда компилятор сделал все правильно. Согласно integer promotion rules ваш rules[i].prev_ch перед сравнением приводится к int и он никак не может быть равным отрицательному числу. Надо или в #define или в условиях явно привести эти константы к uint8_t.
ARV
скачал с сайта Атмела текущую версию тулчейна для AVR8... ща попробую рекомендованную Вами скачать.

Цитата(Сергей Борщ @ Mar 2 2015, 13:20) *
Тогда компилятор сделал все правильно. Согласно integer promotion rules ваш rules[i].prev_ch перед сравнением приводится к int и он никак не может быть равным отрицательному числу. Надо или в #define или в условиях явно привести эти константы к uint8_t.
еще раз и помедленнее, пожалуйста. в моем понимании беззнаковый байт -1 это всего-навсего 0xFF, и потому должен сравниваться...
demiurg_spb
hint:
Код
#define NO_CHAR        -1U
#define ANY_VAR        -2U
#define ANY_DIG        -3U
#define ANY_CHAR    -4U
ARV
блин, Сергей, ну спасибо Вам! как я лоханулся-то! действительно, переделал константы на 0xFF, 0xFE и т.д. - появились проверки!!!
спасибо огромное!

этого самого integer promotions в данном месте и не увидел вообще, незаметно подкрался...
demiurg_spb
Цитата(ARV @ Mar 2 2015, 12:24) *
скачал с сайта Атмела текущую версию тулчейна для AVR8...
А какая версия последняя?
Наберите в консоли:
Код
avr-gcc --v

ARV
все, тему можно закрывать blush.gif

Цитата(demiurg_spb @ Mar 2 2015, 13:30) *
А какая версия последняя?
Наберите в консоли:
Код
avr-gcc --v

4.8.1

хотя еще рано закрывать тему: просветите еще, пожалуйста, как правильно определять массив в flash:
1. __flash const bla_bla_bla array[];
2. const bla_bla_bla __flash array[];

Eclipsе не распарсивает второй вариант, хотя вроде как он правильный...
Сергей Борщ
Цитата(ARV @ Mar 2 2015, 11:34) *
хотя вроде как он правильный...
По моему тоже. Эклипс несовершенен. Можно попытаться направить им сообщение об ошибке.
ARV
у меня с английским не очень хорошо, а автопереводчикам не очень доверяю...

Eclipse Luna мало того, что второй вариант объявления не понимает, но если такое объявление находится в числе параметров функции - вся функция не подсвечивется, и ниже по коду могут быть сбои парсера синтаксиса...
AHTOXA
Цитата(ARV @ Mar 2 2015, 14:49) *
Eclipse Luna мало того, что второй вариант объявления не понимает, но если такое объявление находится в числе параметров функции - вся функция не подсвечивется, и ниже по коду могут быть сбои парсера синтаксиса...

Эклипса понятия не имеет, что такое "__flash". Помогите ей, задайте в Project - Properties - C/C++ General - Paths and Symbols - Symbols пустой дефайн "__flash".
demiurg_spb
Цитата(AHTOXA @ Mar 2 2015, 18:56) *
Эклипса понятия не имеет, что такое "__flash". Помогите ей, задайте в Project - Properties - C/C++ General - Paths and Symbols - Symbols пустой дефайн "__flash".

Думаю, что цель DISCOVERY тоже решает эту задачу, но более правильным способом.
Код
#discovery target for Eclipse parser
#usage: make specs_file=${INPUTS}
.PHONY: discovery
discovery:
        $(CC) $(SOURCE_DIRS) $(ALL_CFLAGS) -E -P -v -dD '$(specs_file)'
        $(REMOVE) spec.d
AHTOXA
Думаете, там будет дефайн для __flash? Я в этом сильно сомневаюсь. Ведь __flash - это не дефайн, а квалификатор типа памяти.
demiurg_spb
Цитата(AHTOXA @ Mar 4 2015, 02:02) *
Да, Вы правы, есть лишь дефайн __FLASH, но это не то...
Жаль что нет стандартного способа раскрытия расширений языка для редактора...
Сергей Борщ
Цитата(AHTOXA @ Mar 2 2015, 17:56) *
задайте в Project - Properties - C/C++ General - Paths and Symbols - Symbols пустой дефайн "__flash".
Это если используется самопальный самописный makefile. А если используется какой-то плагин, генерящий makefile исходя из этих установок, то такой define замаскирует ключевое слово при компиляции. А вот если он будет подставляться только при выполении discovery - все будут довольны:
Код
discovery:
        $(CC) $(SOURCE_DIRS) $(ALL_CFLAGS) -D__flash -E -P -v -dD '$(specs_file)'



И по теме основного вопроса - я полагаю, что проблема возникла из-за использования неподходящего типа. В полях prev_ch, curr_ch хранятся символы и поэтому это тот редкий случай, когда надо использовать тип char. Не unsigned, не signed, не тип из stdint.h, а именно классический char. И поскольку NO_CHAR, ANY_VAR, ANY_DIG, ANY_CHAR представляют из себя переопределенные коды символов, их надо обявлять именно как "символ с указанным кодом", т.е. '\xFF', '\xFE', '\xFD', '\xFC'. Тогда не было бы проблемы с неявным расширением до int и не пришлось бы бороться с ней явными приведениями типов.
AHTOXA
Цитата(Сергей Борщ @ Mar 4 2015, 12:45) *
Это если используется самопальный самописный makefile. А если используется какой-то плагин, генерящий makefile исходя из этих установок, то такой define замаскирует ключевое слово при компиляции. А вот если он будет подставляться только при выполении discovery - все будут довольны:
Код
discovery:
        $(CC) $(SOURCE_DIRS) $(ALL_CFLAGS) -D__flash -E -P -v -dD '$(specs_file)'

Если makefile генерится плагином, то откуда там появится цель discovery? sm.gif
А вот для самописного makefile это решение правильнее, чем то, что я написал выше - так мы получим все настройки проекта в одном месте (в makefile).
ARV
не знаю, что такое discovery, но проблема с подсветкой синтаксиса, обозначенная мной, решается тупым typedef __flash const char fchar; - после этого Eclipse прекрасно понимает, что fchar это тип и все подсвечивает правильно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.