Страница 1 из 1
Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 12:03:01
Gurvinok
Есть некая функция которая при вызове должна записать в четыре ячейки внутренней EEPROM нолики. Сброс пароля. Вот функция.
Код: Выделить всё
// Функция сброса пароля в 0000
void clear_password(void)
{
uint8_t i=0;
while(i<4)
{
eeprom_write_byte((uint8_t*)i,0x30);
i++;
}
}
А вот Вонинг:
Warning 5 cast to pointer from integer of different size [-Wint-to-pointer-cast]Ругается вот на это:
При этом функция честно записывает нолики.
Если записать так:
eeprom_write_byte((uint8_t*)&i,0x30);Ругаться не буден, но и работать тоже не будет. Кто знает, в чем загвоздка. Работаю в AtmelStudio 6.2
Re: Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 12:19:01
Hoksmur
Если варнинг перевести - то пишет, что при преобразовании указателя на указатель другого типа могут быть ошибки.
Посмотрите листинг, если всё как надо - можно забыть( но не "православно"). Попробуйте так (пробел поставить):
Код: Выделить всё
// Функция сброса пароля в 0000
void clear_password(void)
{
uint8_t *i=0;
while(i<((uint8_t *)4) )
{
eeprom_write_byte( i,0x30);
i++;
}
}
Указателю вполне можно присваивать значения. А чтобы сравнивать указатель с указателем -
((uint8_t *)4).
Re: Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 12:23:16
Gurvinok
И пробел пробовал, и указатель явно отдельно создавал, тоже самое. Я бы забил на это предупреждение, но устройство будет нещадно использоваться 24 часа в сутки и не дай бог где-нибудь оно вылезет. Причем вне цикла все работает как часы.
Re: Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 12:31:28
Hoksmur
Попробовал у себя, отредактировал пост. теперь всё кошкерно.

Re: Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 12:37:35
Gurvinok
Гениально!

Работает! Я вчера весь вечер на это убил. Замучил Гугл. Огромное спасибо! Надо это дело запомнить, а лучше записать.
Re: Вонинг и EEPROM Mega8A
Добавлено: Пн авг 18, 2014 22:07:04
YS
Кто знает, в чем загвоздка.
Вы используете восьмибитное значение в качестве указателя. Но на AVR указатель по умолчанию занимает 16 бит. Соответственно, компилятор предупреждает, что размер не соответстует, и он дополнит недостающее нулями.
Проблемы могут начаться, если вы захотите записать по адресу, большему чем 255 (особенно опасно в цикле, кстати). Будет переполнение, и запись пойдет по тем же адресам. Так что предупреждение не лишено смысла.
Чтобы втупую избавиться от варнинга, можно сделать так:
Код: Выделить всё
eeprom_write_byte((uint8_t*)((uint16_t)(i)),0x30);
То есть, сначала расширяем i до шестнадцати бит, потом пишем - компилятор не заподозрит подвоха.
Но это косметическое решение, от переполнения это не спасет никак, разумеется. Нормальное решение - объявить i как
uint16_t.
Это вообще жуть.
(uint8_t*)&i - Эта запись значит следующее: эй, компилятор, вот переменная i. Возьми ее адрес и преврати его в указатель на восьмибитное значение. То есть, по факту,
вы пишете не по тому адресу, что хранится в i, а по адресу самой переменной i, только направляя запись в EEPROM. Разумеется, вы вылетаете за пределы EEPROM, вот оно и не работает.
Решение, предложенное
Hoksmur, рабочее, но там слишком много звездочек, в которых при небольшом усложнении легко запутаться. Всю магию с указателями лучше ограничивать одним местом (одной строкой), чтобы в перспективе было легче локализовать источник проблем.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 08:20:07
Gurvinok
(uint8_t*)&i - это мне посоветовали и от безысходности потраченного времени я все же испробовал хотя сам понимал что это бред.

А вот на счет 16 битных указателей я не знал. Надо это дела запомнить. Конкретно для данной задачи программа не должна залезать дальше 48 ячейки, так что переполнение не будет никак. Но замечания очень хорошие и по делу, приму на вооружение на будущее. Спасибо.
Пи.Си.А как это понять? Из eeprom.h Или я еще не проснулся.
Код: Выделить всё
/** \ingroup avr_eeprom
Write a byte \a __value to EEPROM address \a __p.
*/
void eeprom_write_byte (uint8_t *__p, uint8_t __value);
/** \ingroup avr_eeprom
Write a word \a __value to EEPROM address \a __p.
*/
void eeprom_write_word (uint16_t *__p, uint16_t __value);
Пи.Си.Пи.Си.Код: Выделить всё
// Функция сброса пароля в 0000
void clear_password(void)
{
//uint8_t *i=0;
uint16_t i=0;
while(i<4)
{
eeprom_write_byte((uint16_t)i,0x30);
i++;
}
}
А в ответ
Warning 2 passing argument 1 of '__eewr_byte_m8a' makes pointer from integer without a cast [enabled by default] 
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 09:23:29
ARV
Может, вам литературу почитать про указатели?
В последнем примере вы переменную uint16_t принудительно приводите к типу uint16_t, хотя функция ждёт указатель на байт, о чем и варнингует компилятор
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 10:51:15
YS
А вот на счет 16 битных указателей я не знал. Надо это дела запомнить.
Это написано в avr-libc reference.
У каждой архитектуры есть свой размер указателя. Он определяется пределом адресуемой памяти. Если указатель шестнадцатибитный, то, очевидно, памяти может быть максимум 64 кБ. Для AVR этого более чем достаточно (на моделях с большим количеством переключаются страницы памяти).
На x86 размер указателя 32 бита, потому и памяти может быть не более 4 ГБ.
А в ответ
Warning 2
Звездочку забыли.

Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 11:48:31
Gurvinok
Да, звездочку я с просони забыл поставить, но даже с ней не работает. То же предупреждение.
Меня смущает вот эта строка.
Код: Выделить всё
void eeprom_write_byte (uint8_t *__p, uint8_t __value);
Хотя это логично, так как у 8 меги 512 байт и однобайтовым указателем не отделаться.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 12:28:51
YS
но даже с ней не работает
Ох. Правда, почитайте про указатели.
Ваш код должен выглядеть так:
Код: Выделить всё
// Функция сброса пароля в 0000
void clear_password(void)
{
uint16_t i=0;
while(i<4)
{
eeprom_write_byte((uint8_t *)i,0x30);
i++;
}
}
(uint8_t *) -
шестнадцатибитный указатель на
восьмибитное значение.
(uint16_t *) -
шестнадцатибитный указатель на
шестнадцатибитное значение.
(uint32_t *) -
шестнадцатибитный указатель на
тридцатидвухбитное значение.
(void *) -
шестнадцатибитный указатель, просто указатель на что угодно.
eeprom_write_byte((uint16_t)i,0x30); - вы пытаетесь насильно запихать переменную туда, где компилятор ждет указатель, о чем он вам и сообщает.
eeprom_write_byte((uint16_t *)i,0x30); - вы пытаетесь сказать, что ваше 0x30 на самом деле 0x0030 (понятно почему?).
eeprom_write_byte((uint8_t *)i,0x30); - правильно. i - шестнадцатибитное значение, которое мы приводим к указателю на восьмибитное значение. Все ОК.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 12:32:21
Gurvinok
Все далеко не ОК.
Warning 1 passing argument 1 of '__eewr_byte_m8a' from incompatible pointer type [enabled by default]
Если бы все было ОК, я бы тогда не кипятился.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 12:35:45
YS
Если бы все было ОК, я бы тогда не кипятился.
Еще раз проверьте написанное.
uint16_t i;но далее:
(
uint8_t *)i
Это важно. Указатель шестнадцатибитный, но указывает он на восьмибитное значение! Посмотрите мое сообщение выше внимательно.
Вы путаете тип указателя и тип того, на что он указывает.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 12:40:01
Gurvinok
Я понял. Я даже скопировал код и верхнего сообщения. Именно
eeprom_write_byte((uint8_t*)i,0x30); Все равно это предупреждение. Я уже разобрался с указателями, но эта сволочь все равно предупреждает.
(uint8_t *) - шестнадцатибитный указатель на восьмибитное значение.
(uint16_t *) - шестнадцатибитный указатель на шестнадцатибитное значение.
(uint32_t *) - шестнадцатибитный указатель на тридцатидвухбитное значение.
(void *) - шестнадцатибитный указатель, просто указатель на что угодно.
Зы, а вот за это спасибо! Я еще нигде про такое не встречал. Всегда думал что uint8_t = unsigned char и т.д.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 13:20:35
YS
Проверьте свой код. Возможно, проблема в ваших заголовочных файлах?
Я скомпилировал у себя:
Спойлер
Код: Выделить всё
/*
*/
#include <avr/io.h>
#include <avr/eeprom.h>
void clear_password(void)
{
uint16_t i=0;
while(i<4)
{
eeprom_write_byte((uint8_t *)i,0x30);
i++;
}
}
int main(void)
{
clear_password();
// Insert code
while(1)
;
return 0;
}
Вывод компилятора:
Спойлер
Код: Выделить всё
---------- Build: Release in t_avr ----------
[ 50,0%] Compiling: main.c
[100,0%] Linking console executable: bin\Release\t_avr.elf
Output size is 1,81 KB
[ 16,7%] Running project post-build steps
[ 33,3%] avr-size --mcu=atmega8 --format=avr bin\Release\t_avr.elf
AVR Memory Usage
----------
Device: atmega8
Program: 130 bytes (1.6% Full)
(.text + .data + .bootloader)
Data: 0 bytes (0.0% Full)
(.data + .bss + .noinit)
[ 50,0%] avr-objcopy -O ihex -R .eeprom -R .eesafe bin\Release\t_avr.elf bin\Release\t_avr.elf.hex
[ 66,7%] avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex bin\Release\t_avr.elf bin\Release\t_avr.elf.eep.hex
[ 83,3%] avr-objcopy -O binary -R .eeprom -R .eesafe bin\Release\t_avr.elf bin\Release\t_avr.elf.bin
[100,0%] avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O binary bin\Release\t_avr.elf bin\Release\t_avr.elf.eep.bin
cmd /c "avr-objdump -h -S bin\Release\t_avr.elf > bin\Release\t_avr.elf.lss"
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 0 warnings
-
0 errors, 0 warnings.
Компилятор AVR-GCC, WinAVR 20100110.
Всегда думал что uint8_t = unsigned char и т.д.
Определим uint16_t i; Теперь:
(uint8_t)i - "компилятор, обрежь все кроме младшего байта от i и используй оставшиеся 8 бит в выражении"
(uint8_t *)i - "компилятор, значение i - адрес восьмибитного значения. Используй значение i в выражении как адрес."
Пример - разыменование:
*((uint8_t *)i) - "компилятор, в i лежит адрес восьмибитного значения. Возьми это восьмибитное значение и используй в выражении."
*((uint32_t *)i) - "компилятор, в i лежит адрес тридцатидвухбитного значения. Возьми это тридцатидвухбитное значение и используй в выражении."
Разрядность указателя всегда одинакова и определяется платформой. А указывать он может на все что угодно.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 13:34:22
ARV
Gurvinok писал(а):Всегда думал что uint8_t = unsigned char
char не всегда 8 бит

поэтоу и ввели тип, который точно 8 бит
всегда.
YS писал(а):(void *) - шестнадцатибитный указатель, просто указатель на что угодно.
по стандарту Си этот тип указателя совместим с любым иным типом указателей, чем можно пользоваться для исключения варнингов

Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 13:52:56
Gurvinok
Заработало... После того как создал новый проект и переписал все с нуля. Че за глюк так и не понял. Но все равно спасибо, очень полезная информация.
Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 13:56:34
YS
После того как создал новый проект и переписал все с нуля.
Да, у меня такое тоже пару раз бывало. Видимо, глюки IDE в работе с проектом.

Re: Вонинг и EEPROM Mega8A
Добавлено: Вт авг 19, 2014 14:04:27
Gurvinok
Ладно. Пойду искать очередные грабли.
