|
|
  |
Порты AVR и компиляция |
|
|
|
Sep 28 2007, 22:37
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Sep 28 2007, 00:02)  Выпад по поводу данных в EEPROM и FLASH - явно бредовый. Удобная вещь - она всегда удобная.
Зачем мне для обращения к Flash переменной обращаться ч/з подпрограмму?
Это просто яркий пример как можно всё с ног на голову поставить. Давайте посмотрим, на Вашем любимом IAR: Код #include <string.h>
__eeprom char eeString[]="Prived !"; char String[10]="ABCDEFGHIJ";
int main(void) { memcpy(String, (void const *)eeString, 10); memcpy((void *)eeString, String, 10); return 0; } Скомпилируйте этот код и пройдитесь по нему отладчиком, я думаю что результат Вас сильно порадует, особенно второй memcpy P.S Тока не нужно мне рассказывать что этот пример высосан из пальца... Прямое преобразование типов конечно вставлено специально, тока где и когда Вы наткнетесь на такой результат в реальной программе будете знать тока Вы и Ваш доктор в дурке (после отладки такого кода)
|
|
|
|
|
Sep 28 2007, 23:06
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Преимущества они и в Африке преимущества.
Вы прекрасно понимаете, что ими можно не пользоваться. Иными словами, если вас не устраивает по какой то причине прямое обращение к EEPROM либо FLASH памяти, вы можете использовать обращение аналогичное применяемому в WinAVR. Никаких проблем не вижу. Более того вы, естественно можете переписать и сами процедуры обращения. Или использовать свои библиотеки.
У меня действительно один раз было, при применении в одном операторе различных видов памяти, компилятор неверно (точнее не так как я хотел) компильнул. Проблема обнаружилась легко. После локализации места, прошёл оператор по шагам на асме в отладчике. Обнаружил ошибку. Устранилась легко. Прямым приведением типа.
Трагедии никакой здесь нет. Я думаю в WinAVR тоже найдётся немало скелетов в шкафу.
Я, совершенно не приумаляю достоинства WinAVR. Я просто отметил что им не так уж просто пользоваться и привёл свои аргументы. Исключительно исходя из своих наблюдений. Мне оказалось проще и приятнее работать в IAR. В то же время, если человек свободно программирует и в IAR и в WinAVR, то ему это только плюс. Знаний, как известно, лишних не бывает.
|
|
|
|
|
Sep 29 2007, 07:05
|
Частый гость
 
Группа: Участник
Сообщений: 99
Регистрация: 22-03-07
Из: Novosibirsk
Пользователь №: 26 415

|
Если хочется писать PORTB_0 = 1, это можно сделать средствами любого ANSI C совместимого компилятора. Например, как в SDCC для HC08: Код struct __hc08_bits { unsigned int bit0:1; unsigned int bit1:1; unsigned int bit2:1; unsigned int bit3:1; unsigned int bit4:1; unsigned int bit5:1; unsigned int bit6:1; unsigned int bit7:1; };
#define PTB PORTB /* Alias for PORTB */ #define PTB0 ((struct __hc08_bits *)(&PTB))->bit0 #define PTB1 ((struct __hc08_bits *)(&PTB))->bit1 #define PTB2 ((struct __hc08_bits *)(&PTB))->bit2 #define PTB3 ((struct __hc08_bits *)(&PTB))->bit3 #define PTB4 ((struct __hc08_bits *)(&PTB))->bit4 #define PTB5 ((struct __hc08_bits *)(&PTB))->bit5 #define PTB6 ((struct __hc08_bits *)(&PTB))->bit6 #define PTB7 ((struct __hc08_bits *)(&PTB))->bit7 Изменил одну строчку, чтобы работало для AVR. PTB0 = 1, и даже PTB0 = PTB2 будет работать без проблем, причем для всех портов (где-то как sbi/cbi, где-то lds + sts). Написали один раз что-нибудь типа bitio.h, и пользуйтесь. Но лучше ( надеюсь, грамотные люди со мной согласятся) для конкретной задачи шевеления ногой писать макросы или online функции типа led_busy_on(), led_busy_off() и в коде использовать уже их. led_busy = 1, IMHO, хуже, разве что led_busy = ON  ... Операцию = можно перегрузить для eeprom, но это уже будет C++. Про генерацию кода ничего не скажу. Сам использую gcc для разных платформ, включая PC.
|
|
|
|
|
Sep 29 2007, 11:54
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(singlskv @ Sep 29 2007, 01:37)  P.S Тока не нужно мне рассказывать что этот пример высосан из пальца... Прямое преобразование типов конечно вставлено специально, тока где и когда Вы наткнетесь на такой результат в реальной программе будете знать тока Вы и Ваш доктор в дурке (после отладки такого кода)  Ок, аналогичный пример: Код char Str[]="Hello"; char SomeChar; int main(void) { memcpy( (void *)SomeChar, Str, sizeof(Str)); } Проблема здесь та же самая что и в вашем примере, и даже без переменных в eeprom. Поэтому можете также вместе с доктором ковырять и этот код. Ибо когда нет понимания, что происходит в программе и что может происходить - забудьте про (void *).
|
|
|
|
|
Sep 29 2007, 12:46
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(singlskv @ Sep 29 2007, 01:37)  Прямое преобразование типов конечно вставлено специально, И совершенно без понимания. Отсюда сюрпризы и жалобы на компилятор. Подсказка - любой указатель (на RAM) приводится к void * автоматически. Имеено поэтому в прототипе данной функции используется указатель на void* а не на char*. А любой указатель на флеш автоматически приводится к void __flash *. Поэтому в прототипе memcpy_P в качестве источника использован void __flash *. Чтобы если вы ошибетесь - компилятор мог распознать эту ошибку. Аналогично с указателями на __eeprom. Если вы примените __eeprom указатель как аргумент memcpy, компилятор вам выругался, что вы хотите невозможного. Если после этого вы тупо делаете явное приведение (и тем самым отключаете контроль типов) - то кто же вам злобный буратина? Вот вам встречный пример: Код typedef struct { uint8_t ParamA; uint32_t ParamB; my_struct_t ParamC; }config_t;
config_t const __flash Defaults = { 1, 0x12345678, { 'a', 1, 2, } };
struct { config_t Config; uint8_t CRC; } cfg_RAM, __eeprom cfg_EE;
void ReadConfig() { cfg_RAM = cfg_EE; if( CRC(&cfg_RAM, sizeof(cfg_RAM)) != 0) { cfg_RAM = Defaults; cfg_RAM.CRC = CRC(&cfg_RAM.Config, sizeof(config_t)) cfg_EE = cfg_RAM; } } Напишите с функциями то же самое. Как минимум код будет менее понятный и вы не обойдетесь без приведений типов - а они источник потенциальных ошибок, что вы нам продемонстрировали сами чуть выше.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 29 2007, 17:21
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ Sep 29 2007, 15:54)  Ок, аналогичный пример: Код .................... Проблема здесь та же самая что и в вашем примере, и даже без переменных в eeprom. Ну все таки не совсем одно и тоже, я свой пример показал только с точки зрения потенциально проблемной части в использовании __eeprom, а в вашем примере просто нарисован баг который из-за преобразования типов не смог поймать компилятор. Насколько я знаю, в стандарте С вобще нет такого типа void __eeprom *  А вот теперь представьте себе: Код __eeprom char eeString[]="Prived !"; char String[10]="ABCDEFGHI"; int Int=1; long Long=2;
typedef struct { void *ptr; int size; } SomeData;
SomeData* MassivHrenZnaetSKakimiDannimy[10]; ...................... { MassivHrenZnaetSKakimiDannimy[0].ptr = eeString; MassivHrenZnaetSKakimiDannimy[0].size = sizeof(eeString); MassivHrenZnaetSKakimiDannimy[1].ptr = String; MassivHrenZnaetSKakimiDannimy[1].size = sizeof(String); MassivHrenZnaetSKakimiDannimy[2].ptr = ∬ MassivHrenZnaetSKakimiDannimy[2].size = sizeof(Int); MassivHrenZnaetSKakimiDannimy[3].ptr = &Long; MassivHrenZnaetSKakimiDannimy[3].size = sizeof(Long); ............................. ............................. ............................. memcpy(KudatoTam, MassivHrenZnaetSKakimiDannimy[x].ptr, MassivHrenZnaetSKakimiDannimy[x].size); .......................... .......................... } Хрен знает какие данные оказались не совсем хрен знает какими, а все по тому что кое кто придумал свой новый тип данных... __eeprom xxx
|
|
|
|
|
Sep 29 2007, 18:42
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Sep 29 2007, 16:46)  И совершенно без понимания. Отсюда сюрпризы и жалобы на компилятор. А я жаловался на компилятор ? Нет, ну конечно было пару раз когда я указывал на проблемы с оптимизацией, но не более того... Разговор о том что нету в С таких типов __flash xxx и что не стоит этими придуманными типами пользоваться как обычными типами. Цитата Вот вам встречный пример: Код ................ Напишите с функциями то же самое. Как минимум код будет менее понятный и вы не обойдетесь без приведений типов - а они источник потенциальных ошибок, что вы нам продемонстрировали сами чуть выше. Менее понятен/более понятен, это все таки очень субъективные вещи, для меня например значительно более понятным при работе с EEPROM является или прямой вызов функций записи в него, или просто запуск записи с последующей проверкой что запись уже закончилась. При этом вопросов с приведением типов обычно не стоит, поскольку посредством вызова функции я четко указываю о своих намерениях. Тот код который Вы привели конечно выглядит красиво, мой намного зануднее... НО, объясните мне как Вы будете пользоваться такими присвоениями в следующей ситуации: Есть прога: - все события(опросы) синхронизированны(системный тик) например с тактом 200-500мкс - есть одно или несколько прерываний которые получают данные - есть основной цикл который ведет обработку полученных в прерывании данных - НУЖНО, не прерывая обработку, писать некоторые изменения соcтояния проги в EEPROM Где в этой проге можно написать cfg_EE = cfg_RAM ? Момент номер 2, когда Вы пишите cfg_EE = cfg_RAM , Вы принудительно заставляете перезаписывать в EEPROM даже те ячейки которые в данный момент не требуют модификации. Этим Вы осознанно уменьшаете ресурс EEPROM. Во всех моих занудных алгоритмах записи в EEPROM, перед тем как записать байт из какой-то структуры в соответствующее место EEPROM происходит чтение этого адреса и проверка на то, а нужно ли его вобще перезаписывать. Как Вы думаете, в среднем, какой вариант общения с EEPROM будет более быстрым и более надежным(в смысле ресурса EEPROM) ?
|
|
|
|
|
Sep 29 2007, 19:47
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(singlskv @ Sep 29 2007, 20:21)  Ну все таки не совсем одно и тоже, я свой пример показал только с точки зрения потенциально проблемной части в использовании __eeprom, а в вашем примере просто нарисован баг который из-за преобразования типов не смог поймать компилятор. В вашем примере баг абсолютно такой же как и в моем. Ибо нефиг несовместимый тип приводить к PVOID. Цитата Хрен знает какие данные оказались не совсем хрен знает какими, а все по тому что кое кто придумал свой новый тип данных... __eeprom xxx В AVR три адресных пространства. Насколько это удобно или неудобно не вам судить, и не мне. Они просто есть, IAR дает нам простой инструмент доступа к этим адресным пространствам, если вам такой способ доступа не подходит - пользуйтесь другим, более сложным. Цитата для меня например значительно более понятным при работе с EEPROM является или прямой вызов функций записи в него, или просто запуск записи с последующей проверкой что запись уже закончилась. Кому что.. Меня как правило интересует конечный результат, если воспользовавшись фичей X я смогу добиться конечного результата меньшим числом строк кода и не в ущерб наглядности, читабельности программы и скорости испольнения, то обязательно ей воспользуюсь (по крайней мере подумаю об ее использовании). Минусом будет только "Портируемость" внутри семейства и на другие многоадресные семейства МК, а на "протируемость" на одноадресные МК (напр ARM) оно вообще никак не повлияет. Да и палку вы здесь перегибаете. Что может быть понятнее присваивания? x = y;
|
|
|
|
|
Sep 29 2007, 19:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата IAR дает нам простой инструмент доступа Замечу, что чтение из "откуда-попало" куда удобнее (хотя производительность несколько ниже) при использовании указателей с модификатором __generic, реализация которого у IAR есть, а у остальных аналогичного, похоже, даже в проекте нет.
--------------------
aka Vit
|
|
|
|
|
Sep 29 2007, 20:15
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ Sep 29 2007, 23:47)  Да и палку вы здесь перегибаете. Что может быть понятнее присваивания? x = y; Хорошо, будем говорить тока за себя, лично мне очень не нравится ситуация когда x=y; выполняется несколько сот наносекунд, а e=k; (где e - eeprom) выполняется несколько миллисекунд. Ну и остальные отрицательные стороны использования EEPROM как переменных я уже описал выше.
|
|
|
|
|
Sep 29 2007, 20:20
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(singlskv @ Sep 29 2007, 23:15)  e=k; (где e - eeprom) выполняется несколько миллисекунд. Ну и остальные отрицательные стороны использования EEPROM как переменных я уже описал выше. Ну и что?! У eeprom еще и ресурс ограничен, такова уж особенность этой памяти. 100k раз запишете дальше пойдут сбои. Какое это имеет отношение к удобному механизму обращения к этой памяти? Не нравится медленный внутренний eeprom используйте RAM или ставте быстрый внешний FRAM, но удобного способа доступа к нему средствами компилятора уже не будет, придется писать драйвер.
|
|
|
|
|
Sep 29 2007, 20:30
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ Sep 30 2007, 00:20)  Ну и что?! У eeprom еще и ресурс ограничен, такова уж особенность этой памяти. 100k раз запишете дальше пойдут сбои. Какое это имеет отношение к удобному механизму обращения к этой памяти? Похоже Вы невнимательно читаете мои посты, перечитайте пожалуйста №37, и если Вас не затруднит, ответьте на 2 поставленных мной вопроса, продублирую их на всякий случай: НО, объясните мне как Вы будете пользоваться такими присвоениями в следующей ситуации: Есть прога: - все события(опросы) синхронизированны(системный тик) например с тактом 200-500мкс - есть одно или несколько прерываний которые получают данные - есть основной цикл который ведет обработку полученных в прерывании данных - НУЖНО, не прерывая обработку, писать некоторые изменения соcтояния проги в EEPROM
Где в этой проге можно написать cfg_EE = cfg_RAM ?....................... Как Вы думаете, в среднем, какой вариант общения с EEPROM будет более быстрым и более надежным(в смысле ресурса EEPROM) ?
|
|
|
|
|
Sep 29 2007, 20:40
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(singlskv @ Sep 29 2007, 23:30)  [i]НО, объясните мне как Вы будете пользоваться такими присвоениями в следующей ситуации: Есть прога: - все события(опросы) синхронизированны(системный тик) например с тактом 200-500мкс - есть одно или несколько прерываний которые получают данные - есть основной цикл который ведет обработку полученных в прерывании данных - НУЖНО, не прерывая обработку, писать некоторые изменения соcтояния проги в EEPROM Для этой задачи я поставлю исключительно внешний eeprom либо NVRAM и не буду даже морочиться с внутренним, которого судя по условию задачи просто не хватит для хранения какого либо существенного объема статистики. Внутренний eeprom лично я использую только для: хранения параметров конфигурации устройства, хранения информации о рестартах + дамп критических структур в случае перезагрузки по WDT. Цитата Как Вы думаете, в среднем, какой вариант общения с EEPROM будет более быстрым и более надежным(в смысле ресурса EEPROM) ? Я думаю, что вариант общения должен быть обдуманным, т.е. надо минимизировать число записей. При этом инструмент которым непосредственно производится запись/чтение может быть каким угодно, но желательно простым, что нам и дает IAR.
|
|
|
|
|
Sep 29 2007, 20:58
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ Sep 30 2007, 00:40)  Для этой задачи я поставлю исключительно внешний eeprom либо NVRAM и не буду даже морочиться с внутренним, которого судя по условию задачи просто не хватит для хранения какого либо существенного объема статистики. Внутренний eeprom лично я использую только для: хранения параметров конфигурации устройства, хранения информации о рестартах + дамп критических структур в случае перезагрузки по WDT. А мне вот и для всей остальной статистики хватает  Наверное по тому что я не умею пользоваться встроенной EEPROM ? Цитата Я думаю, что вариант общения должен быть обдуманным, т.е. надо минимизировать число записей. При этом инструмент которым непосредственно производится запись/чтение может быть каким угодно, но желательно простым, что нам и дает IAR. Это вы о чем ? Об этой простоте cfg_EE = cfg_RAM ? Ну и где здесь минимизация количества записей ? Свой вариант реализации я уже описал, читаем-проверяем-если нужно пишем, и это все на уровне байта. Раскажите мне как Вы планируете минимизировать количество записей при помощи этой простоты cfg_EE = cfg_RAM ?
|
|
|
|
|
Sep 29 2007, 21:05
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Где в этой проге можно написать cfg_EE = cfg_RAM ? такую операцию нельзя прерывать независимо от компилятора - это АППАРАТНОЕ ограничение. Если это не понимать, то знание особенностей использования диалекта языка и компилятора не помогут. Потому вопрос Цитата объясните мне как Вы будете пользоваться такими присвоениями в следующей ситуации просто не имеет смысла. Если используется внешняя память, о чём упомянул defunct, то задача относится опять же не к компиляторам, а есть вопрос архитектуры программы.
--------------------
aka Vit
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|