Teensy 4.1 с чипами PSRAM объемом 2x8 МБ: external_psram_size=0, но EXTMEM[] char[] работает так, как ожидалось?
Поэтому я купил 2 чипа PSRAM от PJRC с Teensy 4.1 и припаял их (это отвратительная работа, так как я потерял свои чаевые), но все это проверено мультиметром, и соединения прочные.
Я запустил здесь скетч memtest, составленный как в Teensyduino, так и в PlatformIO: https://www.pjrc.com/store/psram.html
Aaaaand external_psram_size в обоих случаях равен 0. Установка размера памяти вручную в программе также не удается (даже при 8 МБ).
Однако... Дополнительные параметры работают, как и ожидалось. Я также не уверен, как адресация mem на самом деле работает с предоставленной программой memtest - она, безусловно, нигде не использует EXTMEM.
Вот мой тестер памяти (запуск до сбоя):
EXTMEM char bigBuf[10000000];
//char bigBuf[10000];
int c = 0;
void setup() {
c = 0;
}
void loop() {
bigBuf[c] = 'a';
Serial.println(bigBuf[c]);
Serial.println(String(c));
c = c + 1000;
delay(1);
}
Вывод с помощью EXTMEM char[]: (как и ожидалось, переполнено до 16 МБ)
a
0
a
100
...
a
16777100
a
16777200
Вывод с внутренним символом mem[]: (как и ожидалось, переполнен при 512K - максимум оперативной памяти 1)
a
0
a
100
...
a
488081
a
489081
В любом случае, я рад, что EXTMEM работает.. Но может ли кто-нибудь объяснить, что происходит с предоставленным memtest? Я признаю, что не очень хорошо прочитал это, но я думал, что доступ к PSRAM возможен только через EXTMEM; как это решается иначе?
@CSoft, 👍1
2 ответа
Лучший ответ:
Боюсь, ваша тестовая программа работает не так, как вы задумали. Я протестировал его с T4.1 без впаянной оперативной памяти, и он дает тот же результат, что и в вашем вопросе.
- Вы не объявили свой массив изменчивым. Таким образом, компилятор может (и, вероятно, будет) просто оптимизировать чтение обратно.
- Даже если вы объявите переменную изменчивой, процессор считывает значение из строки кэша, т. е. вы всегда получаете правильное значение обратно, даже без какой-либо внешней оперативной памяти.
Вот простая тестовая программа, показывающая эффект. Он всегда включает светодиод, даже если на плате нет внешней оперативной памяти.
EXTMEM volatile int test;
void setup()
{
pinMode(13, OUTPUT);
test = 42;
if(test == 42)
{
digitalWriteFast(13, HIGH);
}
}
void loop(){
}
Здесь разборка функции настройки. Это ясно показывает, что процессор пытается сохранить 42 в (несуществующей) внешней оперативной памяти и считывает ее оттуда. Очевидно, что значение обратного чтения берется из строки кэша. (комментарии, добавленные мной)
void setup()
{
7c: push {r3, lr} // pinMode code
pinMode(13, OUTPUT); //
7e: movs r1, #1 //
80: movs r0, #13 //
82: bl 160c <pinMode> //-------------
test = 42;
86: ldr r3, [pc, #20] ; (9c <setup+0x20>) // load r3 with address of 'test' (0x70000000, stored at 0x9C)
88: movs r2, #42 ; 0x2a // load r2 with #42
8a: str r2, [r3, #0] // store content of r2 at address stored in r3. i.e., store #42 0x7000'0000 (EXTRAM)
if(test == 42)
8c: ldr r3, [r3, #0] // volatile forces the compiler to read back 'test' (store it in r3)
8e: cmp r3, r2 // check if equals r2 (contains #42)
90: bne.n 9a <setup+0x1e> // goto 0x9A if not equal
CORE_PIN13_PORTSET = CORE_PIN13_BITMASK; // digitalwritefast code (next 3 lines)
92: ldr r3, [pc, #12] ; (a0 <setup+0x24>) // ...
94: movs r2, #8 // ...
96: str.w r2, [r3, #132] ; 0x84 // -------
9a: pop {r3, pc} // return from setup()
9c: .word 0x70000000 // Address of 'test'; EXTRAM starts at 0x7000'000
a0: .word 0x42004000 // Address of GPIO register for LED
Пол слушает. Я автор этой программы memtest, а также создатель Teensy. Хотя luni64 уже очень хорошо ответил о вашей тестовой программе, надеюсь, я смогу внести некоторую ясность в официальную программу memtest.
Что касается "Я думал, что к PSRAM можно получить доступ только через EXTMEM", действительно, использование массивов или переменных EXTMEM является нормальным способом. Но это не единственный путь. Программа memtest использует указатели с известным диапазоном адресов этих микросхем памяти. Поскольку провода физически подключаются к периферийному устройству "FlexSPI2" внутри чипа, память всегда будет начинаться с адреса 0x70000000. Вы можете найти эту информацию на странице 35 справочного руководства по чипу.
https://www.pjrc.com/teensy/IMXRT1060RM_rev2.pdf
К сожалению, руководство трудно читать и во многом сбивает с толку. Даже на странице 35 он описывает память как "зашифрованный текст", что могло бы иметь место, если бы механизм шифрования шины (упомянутый на странице 184) использовался определенным образом. Шифрование не используется, и если вы прочтете страницу 184, вы увидите, что движок выполняет только дешифрование, поэтому его действительно можно использовать только для памяти, доступной только для чтения, которая предварительно загружена зашифрованными данными.
Дело в том, что мы знаем, что оперативная память всегда начинается с 0x70000000 из-за того, как спроектировано оборудование. Если вы посмотрите на код memtest, вы увидите, что он создает 2 переменные, называемые "memory_begin" и "memory_end", которые являются указателями, используемыми для прямого доступа к памяти в этом известном диапазоне адресов.
Идея теста памяти заключается в том, что вся память заполнена известным шаблоном данных. Такого рода тестирование предназначено для выявления любых (очень маловероятных) внутренних проблем внутри микросхем памяти, когда запись в одно место внутри чипа может привести к повреждению данных в другом месте того же чипа.
Используемый указатель объявлен с "изменчивым", что не позволяет компилятору пытаться оптимизировать фактический доступ к памяти.
После того, как память будет полностью заполнена, вы увидите, что используется функция arm_dcache_flush_delete (). Даже если вы используете volatile, чтобы компилятор не оптимизировал доступ к удаленной памяти, аппаратное обеспечение Cortex-M7 имеет кэш 1-го уровня 32 КБ. Эта функция заставляет процессор ARM Cortex-M7 полностью записывать любые кэшированные данные в сам чип памяти, а затем удалять данные из своего кэша. Обычно эти специальные функции кэша используются только низкоуровневым кодом драйвера, использующим прямой доступ к памяти (DMA), где вам нужно убедиться, что записанные вами данные действительно находятся в памяти, прежде чем давать периферийному устройству указание использовать DMA для прямого извлечения их из памяти (обычно периферийные устройства на основе DMA не могут получить доступ к кэшу), или перед чтением данных, которые периферийное устройство помещает в память с помощью DMA. Обычно вам не нужно возиться с кэшем, но такого рода тестирование оборудования и специальный бенчмаркинг-это другой вид приложений, в которых важно уделять особое внимание кэшу процессора.
Затем вся память считывается обратно, используя указатель volatile, чтобы компилятор не пытался сделать что-то слишком умное. По мере чтения данных каждое 32-разрядное слово сравнивается с написанным исходным шаблоном. Опять же, идея состоит в том, чтобы проверить довольно маловероятный случай, когда память, по-видимому, работает, но теоретически может возникнуть внутренняя проблема, когда запись в одно место вызывает повреждение где-то еще внутри чипа.
Весь тест повторяется много раз. Используются различные фиксированные 32-битные шаблоны. Многие тесты заполняют всю память псевдослучайной последовательностью, конечно, выполняя ту же проверку, когда любое изменение даже на 1 бит во всем диапазоне памяти будет обнаружено и сообщено как сбой. Возможно, это излишне, но я попытался разработать программу memtest в соответствии с лучшими практиками, описанными для тестирования памяти ПК, и именно так эксперты рекомендуют проверять память (на самом деле они рекомендуют еще более сложные и сложные шаблоны... может быть, когда-нибудь я их добавлю).
Надеюсь, это поможет ответить на вопрос "может ли кто-нибудь объяснить, что происходит с предоставленным memtest?"
Что касается пайки, проблема, с которой сталкивались другие люди, связана с тем, что припой прилипает только к контакту микросхемы памяти. Несмотря на то, что при взгляде сверху это выглядит нормально, возможно, что припой представляет собой каплю, расположенную чуть выше поверхности прокладки на печатной плате. Я бы рекомендовал повторно нагреть припой. Дайте ему время полностью нагреться и стечь на подушку. Хотя дополнительное время нагрева не является замечательным для чипа PSRAM, эти чипы имеют довольно большой размер тепла, и если память не работает, вам действительно нечего терять. Подсчет до 10 при повторном нагреве припоя обычно работает. Если у вас есть какое-либо жидкое химическое вещество, нанесение его перед повторным нагревом также может помочь.
Сначала сосредоточьте свои усилия по ремонту на чипе, установленном на меньшем наборе прокладок рядом с краем печатной платы. Код запуска ищет первый чип размером 8 МБ в этом месте. If даже не будет искать другой чип, если в первом месте не будет обнаружено памяти.
Забавно, что АСЕ заставил меня просмотреть ваш "поздний ответ". Ну, знаете, чтобы убедиться, что это соответствует стандартам. Боже, я не знаю... Я думаю, все в порядке. =), @timemage
- Вложенный цикл
- В чем разница между выводами SCLK и CLK?
- Как прервать соединение HM10 Bluetooth?
- C++ Undefined reference to 'Class:Function()'
- Быстрее TimerOne с Teensy 4.0 (600 МГц)
- Последовательная связь между Teensy и Teensy через USB-разъем
- Какой аналог PORTx для Teensy (4.0)?
- 5 В MCP2515 в 3.3V Teensy. Как уменьшить напряжение MISO
Спасибо за информацию; странно, что EXTMEM решает выйти из строя только при 16 МБ, но, похоже, именно это и происходит. Вы были правы - я попытался на самом деле прочитать значение, присвоенное в начале массива EXTMEM объемом 14 МБ, и ничего не получил. Я прочитал кое-что в теме бета-тестирования Teensy4.1 (я думаю, на форуме Arduino) о паре цифровых выводов, используемых для обнаружения микросхем PSRAM... Мне придется как - то разобраться в этом или надеяться, что у кого-то есть другие идеи (я предполагаю, что я, возможно, поджарил одну пайку-я отпаяю ее и посмотрю, поможет ли это). Thx опять же, никогда не используйте C, поэтому даже не рассматривал volatile., @CSoft