Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: MMU D-Cache I-Cache для ARM926EJ-S
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
ZED
Доброго всем здравия!

Уважаемые специалисты, помогите разобраться с этими монстрами.
Имеется AT91SAM9260 на базе процессора ARM926EJ-S. Для повышения скорости работы нужно настроить:

1) MMU (Memory Management Unit) - Блок управления памятью. Он отвечает за управление доступом к памяти, запрашиваемым центральным процессором путем трансляции адресов виртуальной памяти в адреса физической памяти. MMU разделяет виртуальное адресное пространство на участки одинакового размера (4 Кб, 64 Кб или 1 Mb ) называемые страницами.
Процесс обращается к памяти с помощью адреса виртуальной памяти, который содержит в себе номер страницы и смещение внутри страницы. Процессор преобразует номер виртуальной страницы в адрес соответствующей ей физической страницы при помощи буфера ассоциативной трансляции.
Младшие n бит адреса (смещение внутри страницы) остаются неизменными. Старшие биты адреса представляют собой номер (виртуальной) страницы. MMU обычно преобразует номера виртуальных страниц в номера физических страниц используя TLB(Translation Lookaside Buffer) - Буфер Ассоциативной Трансляции.
Вопрос 1. Как настроить это MMU для указанного выше процессора? Как организовать и заполнить TLB? Как ее подключить к MMU и пользоваться ей?

2) Нужно настроить D-Cache (Data Cache - Кэш данных) и I-Cache (Instruction Cache - Кэш комманд процессора).
Кэш — это некий промежуточный буфер, содержащий информацию, которая может быть запрошена с наибольшей вероятностью. Доступ к данным в кэше идёт быстрее, чем выборка исходных данных из внешней памяти. Таким образом комманды и данные выбираются из быстрее и производительность растет.
Кэш состоит из набора записей. Каждая запись ассоциирована с данными, являющимися копией данных в основной памяти. Каждая запись имеет идентификатор, определяющий соответствие между элементами данных в кэше и их копиями в основной памяти.

Области (сегменты) основной памяти жёстко привязываются к строкам кэш-памяти (в каждой строке могут быть данные из фиксированного набора адресов), что значительно сокращает время поиска. С каждой ячейкой ОЗУ может быть связано более одной строки кэш-памяти. Таким образом, одна запись в Кэше может содержать несколько комманд (наиболе часто употребляемых) из сооветствующей области памяти.

Вопрос 2. Как инициализировать D-Cache и I-Cache? Как и когда (при каких условиях) их очищать? Как с ними работать?


Что имеется у меня: ARM926EJ-S Technical Reference Manual - написано много, очень грузно, четких инструкций не обнаружено. Много всяких режимов, я так и не понял какой нужен именно мне.
Имеется пример, а точнее функции от IAR, но ни в одном проекте они не применяются, т.е. функции нигдек не используются. Тем самым я не могу понять последовательность действий при инициализации вышеупомянутых модулей. Также есть пример из темы данного форума Производительность SAM9XE, непонятки с этим процом. Там есть как раз пример Translation Table, но не очень понятно как с ней работать и почему именно такие адреса.

В ARM926EJ-S еще есть некий регистр TTBR - Translation Table Base Register - я так понял, это регистр указателя начального (базового) адреса расположения TLB. Вопрос где хранить TLB и по какому адресу?


У меня никак не может сложиться общая картина совместной работы этих модулей. Буду признателен специалистам, которые смогут прояснить мне эти вопросы.
DpInRock
Код
unsigned int AT91F_ARM_ReadControl()
{
    register unsigned int ctl;
    ctl = __MRC(15, 0, 1, 0, 0);
        return ctl;
}

void AT91F_ARM_WriteControl(unsigned int ctl)
{
     __MCR(15, 0, ctl, 1, 0, 0);
}

void AT91F_ARM_WriteTTB(unsigned int ttb)
{
    __MCR(15, 0, ttb, 2, 0, 0);
}
void AT91F_ARM_WriteDomain(unsigned int domain)
{
    __MCR(15, 0, domain, 3, 0, 0);
}

void AT91F_InitMMU(void)
{
unsigned int   *TLB  =(unsigned int *) (0x21FF8000);//last 32 K
unsigned int i,ctl;
    // Program the TTB
AT91F_ARM_WriteTTB(0x21FF8000);
AT91F_ARM_WriteDomain(0xFFFFFFFF); // access are not checked
for (i = 0; i < 4096; ++i) TLB[i] = 0;
TLB[0x0]   =  (0x000<<20)|(1<<10)|(15<<5)|(1<<4)|(2<<2)|0x2;
TLB[0x200] =  (0x200<<20)|(1<<10)|(15<<5)|(1<<4)|(2<<2)|0x2;//screen
for (i=0x201;i<(0x201+31);i++)
    TLB[i] = (i<<20)|(1<<10)|(15<<5)|(1<<4)|(3<<2)|0x2;  
TLB[0x006] = (0x006<<20)|(1<<10)|(15<<5)|(1<<4)|0x2; // LCD

TLB[0x21E] = (0x21E<<20)|(1<<10)|(15<<5)|(1<<4)|(0<<2)|0x2; //Peripheria    
TLB[0x21F] = (0x21F<<20)|(1<<10)|(15<<5)|(1<<4)|(1<<2)|0x2; //Peripheria    

TLB[0xFFF] = (0xFFF<<20)|(1<<10)|(15<<5)|(1<<4)|0x2; //Peripheria    

//enable MMU
    ctl = AT91F_ARM_ReadControl();
    ctl |= (1 << 0);
    AT91F_ARM_WriteControl(ctl);
//enable I
        ctl = AT91F_ARM_ReadControl();
    ctl |= (1 << 12);
    AT91F_ARM_WriteControl(ctl);
//enable D
    ctl = AT91F_ARM_ReadControl();
    ctl |= (1 << 2);
    AT91F_ARM_WriteControl(ctl);
}


Это для 9261.
Все виртуальные адреса совпадают с физическими.
ZED
Спасибо DpInRock за Ваш пример. А не могли бы вы описать принцип заполнения TLB.И пояснить как и когда (при каких условиях) очищать кэши? Я просто хочу у сеяб в голове сложить целостную картину.
DpInRock
Просто почитайте что-нибудь для начала. Ответить на конкретный вопрос - нет проблем. Читать курс лекций - не тот формат.
В мануале про заполнение TLB четко написано. Что означает каждый бит. А я уже успел забыть подробности.
Могу посоветовать только смотреть код и мануал одновременно. И говорить ... ага... (так протяжно и задумчиво).


Кэш инструкций надо очищать, если вы пишете что-то в область кода (и собираетесь этот код в ближайшем будущем исполнить) - действие не рекомендуемое (в плане, писать что-то в область программ поверх другого кода, который уже исполнлся когда-либо).

Данные можно не очищать. Но кэшироваться не должны аппаратные регистры. Я лично не кэширую память экрана.

Иными словами, если вы не извращенец - про все типы кэшей - включить и забыть.

Посему подстройте мой код под свои адреса, инит - и забыть про все.

Наскоко помню у 9260 совсем мало SRAM и код у вас будет из SDRAM? наверное...
Тогда типа рекомендация.
Сначала загрузить программу (не включая кэша и прочая), а уже из самой программы все это инициализировать. Не будет лишних вопросов и кэш будет чище.
ZED
Я так понял, что Ваша таблица TLB располагается в SDRAM. Базовый адрес TBL 0x21FF 8000.
Сама программа у Вас располагалась в SRAM? начиная с адреса 0x30 0000.
Строчка
Код
TLB[0x006] = (0x006<<20)|(1<<10)|(15<<5)|(1<<4)|0x2; // LCD
видимо отключает кэширование и буфферизацию LCD.

Код
TLB[0x0]   =  (0x000<<20)|(1<<10)|(15<<5)|(1<<4)|(2<<2)|0x2;

Это для Boot Memory.

Я просто тут немного запутался, разве нам не нужно кэшировать весь Boot Memory, т.е. адреса 0x0000 0000 .. 0x0010 0000? Или достаточно указать только начальный адрес?

Что делает эта строчка и для чего нужен режим Write-Back почему не Write-Trough:
Код
for (i=0x201;i<(0x201+31);i++)
    TLB[i] = (i<<20)|(1<<10)|(15<<5)|(1<<4)|(3<<2)|0x2;


Видимо я не совсем понимаю, что скрывается за понятием адреса в битах [31:20] Form the corresponding bits of the physical address for a section.
DpInRock
У 9261 - 192К SRAM. (у 9260 совсем мало кажется).
В SDRAM у меня ничего такого не располагается. И вам не советую. Все самое дорогое и заветное - в Срам.

При работе учитывайте ремапинг.!!!!!

Укажите Write-Trough. Мне больше нра Write-Back.

То и значит. Соотв. адресные биты этой секции.

Боюсь соврать сильно.
Каждый эл. ТЛБ - это мегабайтаня страница физической памяти от 0 до 4 гиг.
Внутрь элемента вы пишите свойсва этой физической страницы, а заодно и старшую часть виртуального адреса, которому будет соотв. эта физическая страница.

Эта хрень имеет отношение к защите памяти, виртуального адресного пространства для защиты программ друг от друга в ОС. В нашем сельском хозяйстве это вообще нафик не уперлось. Посему виртуальные адреса в моем случае совпадают с реальными. Все виды защит выключены. Ибо я сам распоряжусь памятью и советы всяких там ММУ мне не нужны.
aaarrr
Цитата(DpInRock @ Dec 27 2010, 20:25) *
Боюсь соврать сильно.

Таки получилось sm.gif Индексом в Translation Table служат виртуальные адреса, дескрипторы описывают привязанные к ним физические.
DpInRock
НУ может быть. Уже год как не лазил в 926. А то и больше....
Я ж говорил - лучше читать (это топикастеру). Пробовать. Главное - аккуратно.
Мелкими шажками. Чтоб точно знать, когда ММУ завалило вашу программу, а когда не ММУ.
vmp
Цитата(DpInRock @ Dec 27 2010, 12:58) *
Иными словами, если вы не извращенец - про все типы кэшей - включить и забыть.

Очень опасный совет. Дело в том, что у ARM9 кеш-контроллер и DMA ничем не связаны, так что если работать по DMA с кешируемой памятью, то можно поиметь целую кучу непонятных глюков.
Поэтому про кеши надо помнить, чтобы не создать буфер DMA в кешируемой области памяти.
В том примере у меня один из 32 мегабайтов ОЗУ отводился именно под такие буфера. Заодно туда и TLB засунул. Адреса в примере определяются конфигурацией железа (SAM9XE).
ZED
Может я чего-то не понимаю, но по карте памяти адресу 0x21FF 8000 соответствует область EBI Chip Select 1/SDRAMC. Если я ничего не путаю, то Remap всего лишь отображает SRAM на нулевой адрес 0x0000 0000. Тогда нижеуказанная строчка, которая задает начальный адрес расположения таблицы TLB 0x21FF 8000, определяет расположение этой таблицы в SDRAM?
Код
unsigned int   *TLB  =(unsigned int *) (0x21FF8000);//last 32 K
.

Правильно ли я понял, что программа у меня будет лежать в SDRAM, тогда мне таблицу нужно разместить, например в SRAM1, базовый адрес расположения таблицы тогда будет 0x30 0000 (Расположение SRAM1 на карте памяти), а в саму TLB записывать адреса расположение программы, т.е начальные адрес SDRAM, т.е. 0x2000 0000.
DpInRock
Да.
Зачем я туда засунул эту таблицу - не помню. Пожалел 16k скорее всего.
Тогда да.

Видите, как я выполняю принцип - сделал - и забыл.
Но у вас наверное нет столько памяти... Но если есть - лучше все в срам запихать.
---
Где-то внутри примеров ИАР есть пример с MMU.
ZED
А можно еще такой вопрос? Поскольку у меня такие маленькие размеры SRAM (4 Кб) мне нужно делить память на блоки по 4 Кб? И если все делить не Мегабайтными страницами (Section), а блоками по 4 Кб (Coarse page). Тогда получается, что необходимо два дескриптора: грубый (1-ого уровня) и точный (2-ого уровня). Как тогда вести описание?
Я предполагаю так:

1) Задать базовый адрес расположения Грубого дескриптора что-то типа (размещаю в SRAM1, она у меня 4 Кб):
Код
unsigned int   *TLB  =(unsigned int *) (0x30 0000);//last 32 K


2) Заполнить ее базовыми адресами точного дескриптора (Coarse page table base address) т.е. проинициализировать TLB;

3) Задать базовый адрес расположения точного дескриптора. Тут вопрос куда его положит, во всю ту же SRAM1? Ну напримерпо адресу 0x30 0500 (последний адрес: 0x30 1000). И вопрос хватит ли мне ее? По идее не хватит, мне нужно описать 4096

4) Заполнить (проинициализировать) точные дескрипторы.


Или такой вариант: Структура:
Код
typedef struct __TTL {
    unsigned int Descriptor_1;         // Дескриптор 1-ого уровня
    unsigned int Descriptor_2[256]; // Дескриптор 2-ого уровня
} TTL;



И еще вопрос, откуда переферия по этим адресам (0x21E0 0000 и 0x21F0 0000):
Код
TLB[0x21E] = (0x21E<<20)|(1<<10)|(15<<5)|(1<<4)|(0<<2)|0x2; //Peripheria    
TLB[0x21F] = (0x21F<<20)|(1<<10)|(15<<5)|(1<<4)|(1<<2)|0x2; //Peripheria
DpInRock
Периферия по этим адресам - это копипасте строчек с периферией. (Экран у меня с 2000 0000).

Нет необходимости ВООБЩЕ думать о распределении страниц и прочего. Надо сделать, чтоб реальные совпадали с виртуальными.

Ибо наскоко помню, вся это возня с ММу связана с тем, что нельзя включить кэш не заполнив эту таблицу. Т.е. все это исключительно ради кэша.
SII
Кэш инструкций включается установкой соответствующего бита в управляющем регистре. Кэш данных можно включить только в том случае, если включено MMU, а чтобы его включить, надо сначала подготовить таблицы переадресации. Если виртуальная память и защита памяти не нужны (т.е. если MMU включается исключительно ради кэша), то есть смысл использовать секции, а не страницы, и всё отображение памяти описать одной таблицей первого уровня (4096 элементов по слову каждое, всего 16 Кбайт). Что же касается TLB, то он, как и кэши, работает автоматически, и вручную манипулировать им необходимо лишь в весьма специфических случаях.

Если с английским проблемы, можно посмотреть на ru.osdev.wikia.com.
ZED
Цитата
MMU включается исключительно ради кэша), то есть смысл использовать секции, а не страницы, и всё отображение памяти описать одной таблицей первого уровня (4096 элементов по слову каждое, всего 16 Кбайт).


Это получается, что у меня таблица по-любому не влезет в SRAM1 объемом 4 Кб. Тогда получается, что TLB нужно хранить в SDRAM?
vmp
Цитата(ZED @ Dec 28 2010, 13:46) *
Тогда получается, что TLB нужно хранить в SDRAM?

И какие в этом проблемы? В моем примере так и сделано.
sergeeff
Цитата(vmp @ Dec 28 2010, 15:44) *
И какие в этом проблемы? В моем примере так и сделано.


Единственное, надо чтобы TLB лежала в некешеруемой области sdram.
ZED
Цитата
И какие в этом проблемы?

Да проблем с этим нет. Вы не могли бы мне объяснить назначения доменов и соответственно битов AP?

Вот привожу, что у меня получилось:

Небольшие уточнения, правильно ли я понимаю: TLB располагаем в конце SDRAM, основную программу вначале (я для кэшируемой области памяти выделил первые 32 Мб), инициализируем ее как Write-Back, переферию делаем некэшируемой. Все, TLB готов!

Если я хочу задать переменную в некэшируемой области памяти, то беру адрес, для которого TLB = 0, ну например 0x2350 0000. Тогда объявляем указатель:
Код
unsigned int *variable =  (unsigned int *) (0x2350 0000);
variable = 1234; // присваевыем, как пример, число переменной

P.S. SII, спасибо Вам за ссылку!
vmp
Цитата(ZED @ Dec 28 2010, 16:01) *
Да проблем с этим нет. Вы не могли бы мне объяснить назначения доменов и соответственно битов AP?

Это для защиты памяти при многозадачной работе в общем адресном пространстве. Типа каждой задаче - свой домен, чужие объявляем недоступными.

Цитата(ZED @ Dec 28 2010, 16:01) *
Если я хочу задать переменную в некэшируемой области памяти, то беру адрес, для которого TLB = 0, ну например 0x2350 0000. Тогда объявляем указатель:
Код
unsigned int *variable =  (unsigned int *) (0x2350 0000);
// [b]Забыта *[/b]
[b]*[/b]variable = 1234; // присваевыем, как пример, число переменной

Я бы порекомендовал использовать возможности компилятора:
Код
#pragma location="NO_CACHE"
unsigned int variable;
variable = 1234; // А вот тут без звездочки

В файле конфигурации линкера надо объявить секцию NO_CACHE и разместить ее в соответствующих адресах.
В этом случае можно будет достаточно просто объявлять множество таких переменных, не занимаясь ручным заданием адресов
Кстати, даже первый вариант можно описать в виде:
#define variable (*(unsigned int *) (0x2350 0000))
DpInRock
Чисто совет. Кэш - отличная штука. Ускоряет так нормально.
И если не мудрить, то просто работаешь как обычно.
Кэшируемая или не кэшеруемая память - это важно лишь в очень специфических случаях. В обычной жизни такие случаи не встречаются.

И еще не имеет особого смысла, особенно для 9260 кэшировать СРАМ. Ибо врядли вы там будете прямой доступ к памяти организовывать, а быстродействие кэша и СРАМ одинаковое. (Кэш срам полезен, когда в ней не только программа работает, но и область прямого доступа есть. Тогда программа работаетв кэше, а память свободна для DMA).
aaarrr
Цитата(sergeeff @ Dec 28 2010, 15:47) *
Единственное, надо чтобы TLB лежала в некешеруемой области sdram.

Ни малейшей необходимости в этом нет.

P.S. TLB = Translation Lookaside Buffer, а таблица называется Translation Table.
ZED
Блин код забыл прикрепить:
CODE
unsigned int AT91F_ARM_ReadControl()
{
register unsigned int ctl;
ctl = __MRC(15, 0, 1, 0, 0);
return ctl;
}

void AT91F_ARM_WriteControl(unsigned int ctl)
{
__MCR(15, 0, ctl, 1, 0, 0);
}

void AT91F_ARM_WriteTTB(unsigned int ttb)
{
__MCR(15, 0, ttb, 2, 0, 0);
}
void AT91F_ARM_WriteDomain(unsigned int domain)
{
__MCR(15, 0, domain, 3, 0, 0);
}


//-----------------------------------------------------------------------------
// Размер страницы = 4 Kб (0x1000)
// Раскладка по памяти:
// 0000 0000 - Boot Memory
// 0010 0000 - ROM, не используется (32 Кб)
// 0020 0000 - SRAM0 (4 Кб)
// 0030 0000 - SRAM1 (4 Кб)
// 0050 0000 - UHP (16 Кб)
// 2000 0000 - SDRAM (32 Mб)
// 4000 0000 - NAND DATA
// 4020 0000 - NAND ADDR
// 4040 0000 - NAND CMD
// FFF0 0000 - Периферия
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Описания секций:
// [1..0] = "01";
// 2 - B - Bufferable;
// 3 - C - Cacheable;
// 4 - '1';
// [8..5] - Domain = "1111";
// 9 = '0';
// [11..10] - AP;
// [19..12] = "00000000"
// [31..20] - Базовый адрес секции

// Биты AP
// 01 - Нет доступа (No Access)
// 10 - Только чтение (Read-only)
// 11 - Чтение/Запись (Read/write)

// Биты C и B:
// 0 0 - Не Кэшируемая, Не Буферизируемая
// 0 1 - Не Кэшируемая, Буферизируемая
// 1 0 - Write-Trough-кеш
// 1 1 - Write-Back-кеш
//-----------------------------------------------------------------------------

#define TLB_ADDR 0x2F000000 // Базовый адрес расположения TLB в памяти
#define TLB_NCNB 0xDF2 // Noncachable, Nonbufferable 11 0 1111 1 00 10
#define TLB_WT 0xDFA // Write-through 11 0 1111 1 10 10
#define TLB_WB 0xDFE // Write-back 11 0 1111 1 11 10

// Инициализация MMU:
void AT91F_InitMMU(void)
{
// TLB располагается в SDRAM
unsigned int *TLB = (unsigned int *) (TLB_ADDR);
unsigned int i, ctl;

// Инициализация TTB:
AT91F_ARM_WriteTTB(TLB_ADDR); // Записать начальный адрес расположения TTB (CP15 c2)
AT91F_ARM_WriteDomain(0xFFFFFFFF); // Domain Access Control Register (CP15 c3)

// Очистка TLB:
for (i = 0; i < 4096; ++i) TLB[i] = 0;

// После Reamp по адресу 0x00000000 расположена SRAM0:
TLB[0x000] = 0x00000000 | TLB_WB;

// После Reamp по адресу 0x00100000 расположена ROM:
TLB[0x001] = 0x00100000 | TLB_NCNB;

// SRAM1:
TLB[0x003] = 0x00300000 | TLB_WB;

// UHP:
TLB[0x005] = 0x00500000 | TLB_WB;

// Код основной программы, расположенный в SDRAM (32 Мб):
for (i = 0x200; i < 0x200 + 31; i++){
TLB[i] = (i << 20) | TLB_WB;
}

// Переферия:
TLB[0xFFF] = 0xFFF00000 | TLB_NCNB

//Разрешить MMU
ctl = AT91F_ARM_ReadControl();
ctl |= (1 << 0);
AT91F_ARM_WriteControl(ctl);
//Разрешить I-Cache
ctl = AT91F_ARM_ReadControl();
ctl |= (1 << 12);
AT91F_ARM_WriteControl(ctl);
//Разрешить D-Cache
ctl = AT91F_ARM_ReadControl();
ctl |= (1 << 2);
AT91F_ARM_WriteControl(ctl);
}

Цитата
И еще не имеет особого смысла, особенно для 9260 кэшировать СРАМ

Т.е. эта строчка лишьняя:
Код
  // После Reamp по адресу 0x00000000 расположена SRAM0:
  TLB[0x000] = 0x00000000 | TLB_WB;


Цитата
Чисто совет. Кэш - отличная штука. Ускоряет так нормально.
И если не мудрить, то просто работаешь как обычно.
Кэшируемая или не кэшеруемая память - это важно лишь в очень специфических случаях. В обычной жизни такие случаи не встречаются.


Вот видимо у меня такой случай. Я все это делаю, чтобы запустить EMAC на вышеупомянутом контроллере. И вот в теме, которую я открыл, чтобы с ним разобраться EMAC AT91SAM9260. Так вот в этой теме мне сказали, цитирую:
Цитата
дескрипторы должны быть в не кешируемой области.

Вот поэтому я так все дотошно и спрашиваю, хочу разобраться. Просто еще несколько месяцев назад я вообще не знал что такое ARM процессоры, IAR, J-Link и т.д. Не говоря уже о кэшах, MMU и всего подобного.
DpInRock
Ну и что что в некэшируемой. Ставите нужный битик в описании нужной страницы и все. И она уже некэшируемая.
Всякие там буфера прямого доступа, оне приравниваются по своему сволочизму к аппаратным регистрам.
sergeeff
To ZED:

У Atmel'a, чтобы не было проблем с когерентностью буферов и DMA надо просто все буфера для DMA объявить в некешируемой области. Для этого прислушайтесь к совету vmp. В чистом виде это относится и к EMAC (там еще особые требования по выравниванию адресов таблиц).
aaarrr
Вообще, лучше все же применять творческий подход, а не рубить сразу - тут кэшируем, а тут не кэшируем. Во многих случаях может быть весьма уместен режим write-through (например, у framebuffer'а экрана), построчная или полная инвалидизация кэша (как раз при работе с буферами ПДП), залочка части программы/данных для критичных участков и т.п. Понятно, что сразу подобные упражнения могут и не понадобиться, но списывать их со счетов, один раз все настроив и забыв, совсем не стоит.
ZED
Спасибо Вам большое за советы и помощь!
ZED
Теперь возникли проблемы с PLL. Хотел протестировать работу MMU, для этого написал код дрыгания ножкой. В этом коде есть функция инициализации PLL:
Код
  // Частота медленного RC-генератора SLCK 32.768 кГц. Период 1/32768 = 30.51 мкс
  // Максимальное время запуска основоного генератора: 75 мкс
  // Время запуска основного генератора:8 * OSCOUNT(=16) * 30.51 мкс = 3.9 мс
  // Запуск основного генератора:
  AT91C_BASE_PMC->PMC_MOR = (AT91C_CKGR_OSCOUNT & (0x40 << 8)) | AT91C_CKGR_MOSCEN;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
  // Переключение блока задающей частоты на основную тактовую частоту
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_MAIN_CLK;
  
  // Настройка PLL на частоту 192 МГц:
  AT91C_BASE_PMC->PMC_PLLAR = ( AT91C_CKGR_SRCA                  // 29 бит = 1
                              | (0x2 << 14)                      // OUTA = 2
                              | (0xBF << 8)                      // PLLACOUNT = 191
                              | (AT91C_CKGR_MULA & (0x7C << 16)) // MULA = 124
                              | (AT91C_CKGR_DIVA & 12));          // DIVA = 12
  // Ждать пока пройдет время запуска:
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
  // Выбор задающей частоты и тактовой частоты процессора:
  // Предделитель тактовой частоты PRES = 1, Предделитель задающей частоты MDIV = 2.
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK | AT91C_PMC_MDIV_1;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
  // В качестве основной частоты использовать частоту PLL:
  AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));


Проблема в том, что на строчке:
Код
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;

IAR выдает следующее:
Цитата
Wed Dec 01 12:30:11 2010: The stack 'CSTACK' is filled to 99% (4087 bytes used out of 4096). The warning threshold is set to 90.%
Wed Dec 01 12:30:11 2010: The stack 'IRQ_STACK' is filled to 95% (92 bytes used out of 96). The warning threshold is set to 90.%

Полазил по форуму, там написано, что все дело в REMAP. Пробовал делать REMAP вручную:
Код
AT91C_BASE_MATRIX->MATRIX_MRCR = AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D;

Все тоже самое. Помогите разобраться.

Кстати еще вопрос, с какой примерно частотой у меня должна будет дрыгаться ножка при включенном MMU и Кэшах?
DpInRock
В жизни не получал таких варнингов от ИАР. Скорее всего потому, что стараюсь не передавать слишком много параметров в функции. И слежу за вложенностью...

Ремап никак не связан с варнингами. (Или это симулятор-отладчик такое выдает?)

Ремап надо делать или не делать в зависимости от надобности.

Код
    B       __iar_program_start ; это должна быть первой строчкой вашего стартапа.

__iar_program_start:

/**********************************************************************
* ?CSTARTUP
*
* Execution starts here.
* After a reset, the mode is ARM, Supervisor, interrupts disabled.
*/
?cstartup:
        tst     PC, #0x300000; test for current map
        beq     _after_remap;

    mvn     r0, #0xFF        ;remap here
    bic     r0,r0, #0x1100
    mov     r1, #0x03
        str     r1, [r0, #+0]

_after_remap:


В этом коде проверяется где нах. программа и делается ремап если надо.
Ассемблера АРМ не знаю, делал наугад. Но работает железно.

----
По поводу ковыряния с кэшем - согласен с aaarrr - но только все делать последовательно. Сначала что по проще (написать и забыть), а уж потом, когда придет понимание процессов с одной стороны и нужда - с другой - то можно и потренироваться с управлением кэшем.


Про ножку. Смотря откуда код исполняется... В даташите гляньте - там должна быть указана частота тактирования портов. Вот больше нее - никак. (Если порты тут тактируются - не помню).

Лучше проверять по DBGU. Типа, работает - не работает.
ZED
Цитата
Ремап никак не связан с варнингами. (Или это симулятор-отладчик такое выдает?)

Именно он, когда дохожу до вышеуказанной строчки.

Цитата
Скорее всего потому, что стараюсь не передавать слишком много параметров в функции.

Так функция и не содержит никаких параметров: void Init_CLK(void).
DpInRock
Симуляторы и отладчики - зло.
Вообще тогда смотрите размер стека. Если по умолчанию, то там совсем маленькие стеки (0x10).
А если разрешены вложенные прерывания, то совсем будет плохо....


ZED
В sdram.icf задано:
Код
define symbol __ICFEDIT_size_cstack__   = 0x1000;


P.S. Забыл указать, что прошиваю и отлаживаюсь с помощью J-Link for ARM от IAR System.
DpInRock
А IRQ стек?

Вообще, я отлаживаюсь последовательным интерфейсом. Rs232. Дешево и сердито. А главное - быстро и надежно.

У вас память 2х4к оказывается...
А программа где сама? Кто ее туда грузит? Кто инициализирует стеки?
ZED
Цитата
А IRQ стек?

Код
define symbol __ICFEDIT_size_irqstack__ = 0x60;

Только ругается он на CSTACK.
DpInRock
Насколько я представляю, у вас не отлажена среда работы.

Т.е. вы доверяете ИАРу грузить программу и совершать необходимые манипуляции.
Я лично не так доверчив.

1. Написать свой загрузчик. Который бы грузил нечто в SRAM.
2. Это нечто из SRAM может по командам с PC либо записать что-то во флэшку, либо записать нечто в SDRAM и запустить это нечто (Предварительно, разумеется, инициализировав SDRAM).

Таким образом в ходу будут две программы - маленький загрузчик и основная прогграмма (которая компилируется под SDRAM).

Тут вы управляете всеми процессами ЛИЧНО.
Ну, а отладочная консоль естественным образом проистекает от DBGU.

На все это у вас уйдет пара дней. Зато потом будет легко.


Вообще-то у вас варнинг и на IRQ есть... (0x1000 на CS - это дофига. У меня стоит 0x300. И то столько не нужно. Программа километровая... С переключателем задач, USB, кучей всякой дряни...)
ZED
Ну я вообщето взял готовый проект getting-started-project-at91sam9260-ek и просто вставил туда свой код.
Цитата
1. Написать свой загрузчик. Который бы грузил нечто в SRAM.
2. Это нечто из SRAM может по командам с PC либо записать что-то во флэшку, либо записать нечто в SDRAM и запустить это нечто (Предварительно, разумеется, инициализировав SDRAM).

А можно пример?
SII
Цитата(ZED @ Dec 28 2010, 16:01) *
правильно ли я понимаю: TLB располагаем в конце SDRAM


Неправильно sm.gif TLB -- это внутренний узел устройства управления памятью (MMU), а посему в памяти ну никак находиться не может. Говоря упрощённо, TLB -- это кэш-память, в которой хранятся последние использованные строки таблиц переадресации. А вот эти самые таблицы действительно хранятся в памяти, откуда MMU их по мере надобности считывает и кэширует в TLB.

Местоположение таблиц в памяти роли само по себе не играет, надо лишь обеспечить их правильное выравнивание (граница 16 Кбайт для таблицы первого уровня, если склероз не подводит). Так что выделяете под них то место, какое для Вас лично удобно, и всё.

Цитата(ZED @ Dec 29 2010, 14:58) *
Ну я вообщето взял готовый проект getting-started-project-at91sam9260-ek и просто вставил туда свой код.


К готовым проектам относитесь настороженно и достаточно критически: их качество оставляет желать. Меня в своё время поразил стартовый код для 9261, я даже по этому поводу небольшим сообщением разродился.

Цитата
А можно пример?


Вообще, эта задача, хотя и не слишком сложная, тривиальной тоже не является. Фактически всякие там SAM-BA и прочие средства программирования примерно так и работают: по JTAG загружают в оперативу некий код и запускают его на выполнение, а уже он обеспечивает запись во флэш-память, при необходимости подгружая информацию с ПК. В общем, пример не такой маленький получится, да и не уверен, что найти его просто...
DpInRock
По поводу примера.
Это действительно не так чтоб очень,но большая работа.
Но вполне по силам любому.
ZED
Цитата
По поводу примера.
Это действительно не так чтоб очень,но большая работа.
Но вполне по силам любому.

А счего начать? Я даже не совсем представляю как все это должно выглядеть.
DpInRock
Перед вами плата.
Перед вами PC.
Шнурок RS232 между ними.
Руководящий документ - абзац из даташита с описанием SAM-BA.
------
1. Пишите PC программу, которая сможет загонять в SRAM файл и запускать его.
2. Тренируетесь. Мигаете светодиодами и пр.
3. Теперь загоняете не абы какую программу, а программу, которая умеет взаимодействовать с PC. В целях записи
некоего файла во флэшку. Также с целью заполнения уже SDRAM неким файлом и запуском этого файла.
4. Тренируетесь.
5. Загоняете во флэшку программу, которая:
Загрузившись в SRAM (это делает за вас сам процессор):
1. Инициализирует SDRAM
2. Переписывает туда программу
3. Запускает ея.

Все.

Ну, естественно, RS232 на всех этапах служит для отладки.

Я вот так именно и поступал. Если умеете программировать - там нечего делать практически. Алгоритм SAM-BA - это примерно 3\4 15" экрана в Дельфи.


JeDay
Цитата
1. Пишите PC программу, которая сможет загонять в SRAM файл и запускать его.

Зачем советовать человеку изобретать велосипед? sm.gif Для этих целей есть SAB-BA. Если не будете доверять штатному инструментарию, то у вас не останется времени на сам проект...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.