Jump to content

    
Sign in to follow this  
ДЕЙЛ

Запись флеш в LPC1778

Recommended Posts

Решил данный вопрос задать в отдельной теме, ответвив от темы про стартовый загрузчик http://electronix.ru/forum/index.php?showt...15&start=15

Там подсказали насчёт организации записи флеш из пользовательской программы. Сделал по мануалу, т.к. примеров пока не видел. Получилось вот так:

#include "iolpc1778.h"
#include "LPC17xx.h"
#define IAP_LOCATION 0x1fff1ff1 //точка входа в IAP (страница 896 мануала)  
unsigned long *command;
unsigned long *result;
unsigned int  *test;
typedef void (*IAP)(unsigned int*, unsigned int*);  
void main(void)
{
{ //INIT 
SCS     |= 0x20;          //подключение осциллятора 12МГц 

while(!( SCS & 0x40 )) {} //ожидание запуска 

PLL0CON |= 0x01;          //включение PLL0
PLL0CFG |= 0x09;          //умножение частоты тактирования на (1+9) - 120МГц
PLL0FEED = 0xAA;          //
PLL0FEED = 0x55;          //
CCLKSEL |= 0x100;         //тактирование CPU от PLL0
}
test  = (unsigned int*)0x20001004; //записал контрольный байт в копируемую область RAM
*test = 0xAA;



IAP iap_entry;                              //так в мануале написано
iap_entry = (IAP) IAP_LOCATION; //---//---



//_______СТЕРЕТЬ СЕКТОР_______//
{
result  = (unsigned long*)0x20006100;   //адрес расположения таблицы результатов
command = (unsigned long*)0x20006000;   //адрес таблицы параметров

*command = 52; //код команды
*command++;
*command = 4;  //начальный номер сектора
*command++;
*command = 4;  //конечный номер сектора
*command++;
*command = 120000; //системная тактовая частота в кГц

asm ("mov  r0, #0x6000"); //Запись в регистры отдельно младшие 2 байта
asm ("movt r0, #0x2000"); //и старшие два байта адресов таблиц

asm ("mov  r1, #0x6100"); 
asm ("movt r1, #0x2000");

iap_entry (command, result); 
}
//_______СТЁРЛИ СЕКТОР______// 





//_______ПОДГОТОВИТЬ СЕКТОР К ЗАПИСИ_______//
{
result  = (unsigned long*)0x20006100;   //адрес расположения таблицы результатов
command = (unsigned long*)0x20006000;   //адрес таблицы параметров

*command = 50; //код команды
*command++;
*command = 4;  //начальный номер сектора
*command++;
*command = 4;  //конечный номер сектора

asm ("mov  r0, #0x6000"); //Запись в регистры отдельно младшие 2 байта
asm ("movt r0, #0x2000"); //и старшие два байта адресов таблиц

asm ("mov  r1, #0x6100"); 
asm ("movt r1, #0x2000");

iap_entry (command, result); 
}
//_______ПОДГОТОВИЛИ СЕКТОР К ЗАПИСИ______// 







//_______КОПИРОВАТЬ ОПЕРАТИВНУЮ ПАМЯТЬ ВО ФЛЕШ_______//
{
result  = (unsigned long*)0x20006100;   //адрес расположения таблицы результатов
command = (unsigned long*)0x20006000;   //адрес таблицы параметров 

*command = 51;         //код команды
*command++;
*command = 0x4000;     //начальный адрес перезаписываемой флеш
*command++;
*command = 0x20001000; //начальный адрес оперативной памяти, откуда нужно копировать 

*command++;
*command = 512;        //число байт для копирования
*command++;
*command = 120000;     //системная тактовая частота в кГц


asm ("mov  r0, #0x6000"); //Запись в регистры отдельно младшие 2 байта
asm ("movt r0, #0x2000"); //и старшие два байта адресов таблиц

asm ("mov  r1, #0x6100"); 
asm ("movt r1, #0x2000");

iap_entry (command, result); 
}
//_______СКОПИРОВАЛИ СЕКТОР______// 




while(1)
{
   test  = (unsigned int*)0x4004; //для просмотра ячейки в отладчике в пошаговом режиме. 
}
}

 

 

Работать почему-то не хочет - как было во флеш FFFFFFFFFFFF, так и остались. Ещё в мануале написано, что содержимое регистров r0 и r1 остаётся постоянным во время работы с флеш-памятью, но у меня в пошаговом режиме видно, что после функции iap_entry (command, result); они меняются. Так же там написано, что в регистры r0 и r1 записываются начальные адреса таблиц параметров и результатов. Можно ли в моём коде избавиться от ассемблерных вставок, т.к. каждый раз вручную назначать адреса таблиц в памяти неудобно и нежелательно. Ещё там написано, что верхние 32 байта RAM не должны использоваться пользовательской программой, но как программе запретить пользоваться этими байтами?

 

UP1: добавил файл проекта в IAR

20141001LPC.rar

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites
Работать почему-то не хочет
Перед командой стирания надо выполнить команду подготовки сектора. Запись в регистры асм-вставками бессмысленна - вы делаете то же самое вызывая iap_entry() с параметрами. Во стальном похоже на правду. Вы зарезервировали для IAP место в конце ОЗУ?

Share this post


Link to post
Share on other sites
Перед командой стирания надо выполнить команду подготовки сектора. Запись в регистры асм-вставками бессмысленна - вы делаете то же самое вызывая iap_entry() с параметрами. Во стальном похоже на правду. Вы зарезервировали для IAP место в конце ОЗУ?

С этим тоже вопрос. Как зарезервировать место в памяти?

Share this post


Link to post
Share on other sites
Как зарезервировать место в памяти?
Читать документацию на среду разработки. Или хотя бы указать ее название - возможно кто-то и подскажет. Но читать полезнее :)

 

Share this post


Link to post
Share on other sites
Читать документацию на среду разработки. Или хотя бы указать ее название - возможно кто-то и подскажет. Но читать полезнее :)

среда IAR

 

Вы зарезервировали для IAP место в конце ОЗУ?

В мануале написано, что нужно зарезервировать верхние байты. Что имеется ввиду под верхними байтами, если считать за начало адрес 0x2000000, а за конец 0x2008000? Эти 32 байта распложены в области 0x2000000 - 0x200001F или в другом конце?

 

Share this post


Link to post
Share on other sites
среда IAR
Читайте про линкер и его скрипт. Возможно можно где-то в менюшках уменьшить доступный размер ОЗУ. Просто скажите линкеру, что у вашего процессора ОЗУ меньше на 32 байта.

или в другом конце?
В другом - в самом конце ОЗУ.

 

Share this post


Link to post
Share on other sites
Запись в регистры асм-вставками бессмысленна - вы делаете то же самое вызывая iap_entry() с параметрами.
Не совсем. ТС модифицировал command перед тем, как передавать его в iap_entry(). Так что работать не будет :rolleyes:

 

Share this post


Link to post
Share on other sites

Спасибо, заработало :-)

 

Выкинул ассемблер, упростил и в итоге получился работающий код:

#include "iolpc1778.h"
#include "LPC17xx.h"
#define IAP_LOCATION 0x1fff1ff1 //точка входа в IAP (страница 896 мануала)  
unsigned int command[5];
unsigned int result[2];
unsigned int  *test;
typedef void (*IAP)(unsigned int[], unsigned int[]);  
void main(void)
{
{ //INIT 
SCS     |= 0x20;          //подключение осциллятора 12МГц 

while(!( SCS & 0x40 )) {} //ожидание запуска 

PLL0CON |= 0x01;          //включение PLL0
PLL0CFG |= 0x09;          //умножение частоты тактирования на (1+9) - 120МГц
PLL0FEED = 0xAA;          //
PLL0FEED = 0x55;          //
CCLKSEL |= 0x100;         //тактирование CPU от PLL0
}
test  = (unsigned int*)0x20001004;
*test = 0xAA;



IAP iap_entry;
iap_entry = (IAP) IAP_LOCATION;



//_______ПОДГОТОВИТЬ СЕКТОР К ЗАПИСИ_______//
{

command[0] = 50; //код команды
command[1] = 4;  //начальный номер сектора
command[2] = 4;  //конечный номер сектора

iap_entry (command, result); 
}
//_______ПОДГОТОВИЛИ СЕКТОР К ЗАПИСИ______// 




//_______СТЕРЕТЬ СЕКТОР_______//
{

command[0] = 52;     //код команды
command[1] = 4;      //начальный номер сектора
command[2] = 4;      //конечный номер сектора
command[3] = 120000; //системная тактовая частота в кГц

iap_entry (command, result); 
}
//_______СТЁРЛИ СЕКТОР______// 

//_______ПОДГОТОВИТЬ СЕКТОР К ЗАПИСИ_______//
{

command[0] = 50; //код команды
command[1] = 4;  //начальный номер сектора
command[2] = 4;  //конечный номер сектора

iap_entry (command, result); 
}
//_______ПОДГОТОВИЛИ СЕКТОР К ЗАПИСИ______// 




//_______КОПИРОВАТЬ ОПЕРАТИВНУЮ ПАМЯТЬ ВО ФЛЕШ_______//
{

command[0] = 51;         //код команды
command[1] = 0x4000;     //начальный адрес перезаписываемой флеш
command[2] = 0x20001000; //начальный адрес оперативной памяти, откуда нужно копировать 
command[3] = 512;        //число байт для копирования
command[4] = 120000;     //системная тактовая частота в кГц
  
iap_entry (command, result); 
}
//_______СКОПИРОВАЛИ СЕКТОР______// 

while(1)
{
   test  = (unsigned int*)0x4004;
}
}

 

Интересно узнать, в чём суть подготовки памяти? Со стиранием вроде понятно - наверно FFFFFFFами заполняет всё. И ещё есть не совсем понятная команда заполнения пробелами. Правильно я понимаю, что 0x1fff1ff1 есть адрес начала отдельной программы IAP?

Share this post


Link to post
Share on other sites
Спасибо, заработало :-)
"И совсем не страшно" :)

 

Интересно узнать, в чём суть подготовки памяти?
Это знают только авторы IAP.

Правильно я понимаю, что 0x1fff1ff1 есть адрес начала отдельной программы IAP?
Да.

 

 

Не совсем. ТС модифицировал command перед тем, как передавать его в iap_entry(). Так что работать не будет :rolleyes:
Недопонял. Ну сделал он его указателем, как это повлияло на неработу? Адрес массива передается в функцию точно таким же указателем. Место в памяти под command он выделяет статически. Да, абсолютные адреса-"магические цифры", криво но как может влиять на неработу? Или я чего-то другого не заметил?

 

Share this post


Link to post
Share on other sites
Недопонял. Ну сделал он его указателем, как это повлияло на неработу? Адрес массива передается в функцию точно таким же указателем.

Он несколько раз инкрементировал этот указатель, прежде чем передать в функцию:

command = (unsigned long*)0x20006000;   //адрес таблицы параметров

*command = 51;         //код команды
*command++;  // <<< тут
*command = 0x4000;     //начальный адрес перезаписываемой флеш
*command++; // <<< тут
*command = 0x20001000; //начальный адрес оперативной памяти, откуда нужно копировать

*command++; // <<< тут
*command = 512;        //число байт для копирования
*command++; // <<< и тут
*command = 120000;     //системная тактовая частота в кГц

iap_entry (command, result); // В результате тут command смотрит не на команды, а сразу ЗА НИМИ

Share this post


Link to post
Share on other sites

У меня было ошибочное предположение, что адреса таблиц нужно вписывать в регистры вручную перед вызовом IAP, что я и делал:

asm ("mov  r0, #0x6000"); //Запись в регистры отдельно младшие 2 байта
asm ("movt r0, #0x2000"); //и старшие два байта адресов таблиц

asm ("mov  r1, #0x6100");
asm ("movt r1, #0x2000");

Поэтому в моём представлении инкременты ничего не меняли, но в любом случае вариант кода из первого поста не работал.

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites
Поэтому в моём представлении инкременты ничего не меняли, но в любом случае вариант кода из первого поста не работал.
Так по этому и не работал - передача параметрами command и result полностью забивали то, что вы сделали в ассемблерной вставке. Причем меняли правильные значения в регистрах (после ассемблерной вставки) на неправильные (из модифицированного command)

 

 

Share this post


Link to post
Share on other sites
Так по этому и не работал - передача параметрами command и result полностью забивали то, что вы сделали в ассемблерной вставке. Причем меняли правильные значения в регистрах (после ассемблерной вставки) на неправильные (из модифицированного command)

не работало по причине неправильной программы, это я уже выяснил :) Этот вопрос можно пока закрыть. Лучше посоветуйте в теме про стартовый загрузчик.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this