Страница 1 из 1
ATTiny2313: использование инструкции SPM
Добавлено: Вт фев 02, 2010 13:02:38
eqltv
Хочу использовать память программ для долговременного хранения данных. Почитал AVR109 про самопрошивку и написал такой код (привожу только ту часть, которая пытается работать с памятью программ):
Код: Выделить всё
; Считать байт и проверить его на равенство 0xff
ldi r30, lo8(1024)
ldi r31, hi8(1024)
lpm
inc r0
brne end
; заполнить таблицу словом 0xaa55
ldi r18, 0x55
ldi r19, 0xaa
mov r0, r18
mov r1, r19
ldi r19, PGSIZE
l1: ldi r18, 1
out SPMCSR, r18
spm
adiw r30, 2
dec r19
brne l1
; записать
ldi r30, lo8(1024)
ldi r31, hi8(1024)
ldi r18, 5
out SPMCSR, r18
spm
end:
rjmp end
Ожидается, что в 16 словах с адреса 1024 будет записано 0xAA55. Но они остаются незапрограммированными.
Кроме того, возник вопрос про "bootloader". В описании tiny2313 совсем ничего о нем не сказано, а фьюзы, которыми он управляется, помечены неиспользуемыми. Но про самопрограммирование там есть - запись в любую область памяти останавливает процессор на время записи, как будто вся память образует этот bootloader.
Помогите разобраться и понять, почему не работает код.
Добавлено: Вт фев 02, 2010 13:50:59
GP1
Если я ничего не путаю, вот так из текста программы использовать SPM не получится.
Добавлено: Вт фев 02, 2010 14:12:35
eqltv
GP1 писал(а):Если я ничего не путаю, вот так из текста программы использовать SPM не получится.
А как получится? Откуда ее вызывать, если в даташите ничего про бутлоадер не сказано?
Добавлено: Вт фев 02, 2010 17:08:29
uchar
Могу ошибаца, но мое предположение такое - записывая в регистр Z адрес ячейки, начиная с которой хотите писать свои данные, надо сдвинуть адрес на 1 влево :
Код: Выделить всё
ldi ZL,Low (SerialN<<1)
ldi ZH,High(SerialN<<1)
А дальше после записи каждого байта делать инкремент Z.
Тут все дело в том, что в регистре Z 15 старших бит указывают на адрес ячейки, а младший бит указывает на то, старший или младший байт ячейки вы будете читать/писать.
Полагаю, что сейчас вы пишете во флэш, но только совсем ну туда, куда хотите. У меня все было именно так, только при чтении

Добавлено: Вт фев 02, 2010 17:56:29
eqltv
Написал на C программу (avr-libc) - тоже не работает. Вот код:
Код: Выделить всё
BOOTLOADER_SECTION
void fillPage(unsigned int addr, unsigned int word)
{
int i;
for(i = 0; i < SPM_PAGESIZE; i+=2)
{
boot_page_fill(addr + i, word);
}
}
BOOTLOADER_SECTION
void writePage(unsigned int addr)
{
boot_page_write(addr);
boot_spm_busy_wait();
//boot_rww_enable();
}
BOOTLOADER_SECTION
void erasePage(unsigned int addr)
{
boot_page_erase(addr);
boot_spm_busy_wait();
}
int main()
{
unsigned char b = 0;
unsigned int addr = 0;
unsigned int pgaddr = 0;
lptInit();
while(1)
{
b = lptRecv(0xcc);
addr = 0;
switch(b)
{
case 1: // lpm
addr |= lptRecv(0xa0);
addr |= lptRecv(0xa1)<<8;
lptSend(pgm_read_byte_near(addr));
break;
case 2: // set page address
addr |= lptRecv(0xa0);
addr |= lptRecv(0xa1)<<8;
pgaddr = addr;
break;
case 3: // fill page with word
addr |= lptRecv(0xd0);
addr |= lptRecv(0xd1)<<8;
fillPage(pgaddr, addr);
break;
case 4: // write page
writePage(pgaddr);
break;
case 5: // erase page
erasePage(pgaddr);
break;
case 6: // lpm 2 bytes from pgaddr
lptSend(pgm_read_byte_near(pgaddr));
lptSend(pgm_read_byte_near(pgaddr+1));
break;
default:
break;
}
}
return 0;
}
lpt* - это команды общения с компьютером. Всё работает правильно, кроме записи во флэш. Пытался даже просто стереть страницу с адресом 0, не стерлась.
Почему не работает? Как заставить?
Добавлено: Вт фев 02, 2010 18:05:48
eqltv
Всё, проблема решена. Нужно было запрограммировать бит SELFPRGEN(0) из efuse. Выводы - нужно читать весь даташит, а не только отдельную главу.
Добавлено: Вт фев 02, 2010 18:32:35
uchar
Перечитал документацию ешо раз - все написанное мной выше относица только к чтению данных из флэша, т.е. к команде LPM.
При записи все будет иначе.