Поиск сообщества
Показаны результаты для тегов 'FRAM'.
Найдено: 3 результата
-
Потребовалась в проекте простая и долгоживущая память для вобщем- то небольшого количества данных, на случай сбоя по питанию. Работа ограничивалась записью текущих изменяющихся значений и восстановлением при включении. При неспешной записи несколько раз в минуту, ресурс ATMEGA328 выбирался за 2 года гарантированной записи её родной EEPROM, происходившей по кольцу, что не очень радовало. Отступление небольшое, в нете читал статью где этот чип подвергался повышенным напряжением в 7- 9В и при снижении опять начинал работать, так это правда, случайно проверил. Ещё тестили количество циклов чтения- записи, реально намного превышает количество заявленное производителем, но у меня не тот случай где можно на это надеяться. Присутствовал на борту модуль с Алиекспресса с DS3231, на нём имелась память 24С32. Ввиду чрезвычайного удобства (модуль два в одном, и часы и память, общая шина IIC/TWI) эта микросхема использовалась для вышеуказанных целей очень долгое время. А потом всё устройство обрастало свистелками- перделками многочисленными датчиками и подвергалось давлению перфекционизма. Времени для записи, по даташиту 10ms, стало слишком много и в обрез оставалось для основной работы программы. Я посмотрел в сторону FRAM. Были заказаны на том же Али FM24С64 и 04. Частота работы до 1 Мгц, выпускаются в вариантах 5 и 3,3В, объёма, учитывая количество циклов записи- чтения 10 в 12-й степени хватало. Перепробовав безуспешно адаптировать несколько библиотек, для обычных 24СХХ, решил написать подпрограммы, напрямую работая со встроенной библиотекой Wire Arduino IDE (https://www.arduino.cc/en/Reference/Wire). Этими скетчами проверял присланные микросхемы. Для FM24C04: #include <Wire.h> byte iich = 0x50;// адрес устройства unsigned int address = 0; byte datawrite = 0x77;// чем заполнить ячейки памяти void setup() { Serial.begin(115200); Wire.begin(); Wire.setClock (400000);// скорость шины, от 3,3В через конвертер уровней TXS0108 тоже работают for (address = 0; address < 512; address ++ ) { // цикл для записи в память iic_write (address, datawrite); } for (address = 0; address < 512; address ++ ) { // цикл для чтения из памяти Serial.println (); Serial.print (address); Serial.print ("--"); Serial.print (iic_read (address),HEX); Serial.print ("--"); } } ///////////////////////////////////////////////////// void loop() { } ///////////////////////////////////////////////////// unsigned int iic_read (unsigned int adrd) { Wire.beginTransmission(iich); Wire.write(adrd); Wire.requestFrom(iich, 1); return Wire.read(); Wire.endTransmission(); } void iic_write ( unsigned int adwr, byte dat) { Wire.beginTransmission(iich); Wire.write(adwr); Wire.write(dat); Wire.endTransmission(); } Для FM24С64 меня ждали несколько шикарных, испытанных временем граблей. Перерыт инет, перечитан даташит. Внутренний подтягивающий к земле резистор internally pulled down достаточно велик для уровня наводки, воспринимаемой как логический "0" или "1". Поэтому вывод WP- обязательно к земле наикратчайшим проводом, тем более если это "сопли" на разъёмах на столе. То- же о выводах А0-А2, висящие в воздухе они давали несколько несуществующих адресов. Почему- то это не касается FM24C04 и я попался на этом чипе. Подпрограммы изменились, для чтения: unsigned int iic_read (unsigned int adrd) { Wire.beginTransmission(iich); Wire.write(adrd >> 8);// старший байт Wire.write(adrd & 0xFF);//младший байт Wire.requestFrom(iich, 1); if (Wire.available()) { return Wire.read(); } Wire.endTransmission(); } для записи: void iic_write ( unsigned int adwr, byte dat) { Wire.beginTransmission(iich); Wire.write(adwr >> 8); Wire.write(adwr & 0xFF); Wire.write(dat); Wire.endTransmission(); } Работа 5В версии (FM24C64-G) при питании 3,3В и скорости шины 400000 стабильна, что рекомендовать к работе конечно нельзя. По поводу FM24C64 (подозреваю что и С32 , С128, С256) коротко и ясно написано на https://forum.arduino.cc/index.php?topic=18946.0 пользователь alicemirror объясняет как работает чтение у этих микросхем, а поскольку они прямая замена для, например, АТ24С64, то и для них это справедливо. Дело в том, что данные из микросхемы "выстреливаются" далее без указания адреса с его автоинкрементом самой микросхемой после подтверждения от ведущего. Эту прыть и надо останавливать при получении байта :-) и способ адресации отличается от младших, с меньшим объёмом. Интересных всем проектов!
-
Как часто у вас бывало так, что необходимо хранить данные в ЭСППЗУ, но в текущем МК места не хватало? Приходится брать следующий по уровню МК, хотя во всем остальном он избыточен. В MSP430 на основе FRAM памяти это уже может быть вовсе и не проблемой. Изначально FRAM память поделена на сегменты. В старших моделях таких сегментов 3 с произвольной защитой каждого из них, а в кристалле 2433 всего два сегмента: под код программы и под информационный сегмент. Но вся прелесть в том, что мы можем сохранять свои данные не только в информационном сегменте (у нас он всего 512 байт), но и в сегменте программ. От слов к делу. Сколько будем хранить? У меня IAR с лицензионным ограничением линковщика на 8кБ. Вот давайте столько и запишем =) Подключаем обязательные файлы #include "io430.h" #include "stdint.h" Определяем константу с сохраняемым объемом: #define Write_Size 4000 Создадим массив с вышеприведенным количеством элементов. У нас же архитектура 16 бит? Вот столько и запишем в элемент массива: __persistent uint16_t EEPROM[Write_Size]; директива __persistent - это аналог __no_init с той разницей, что __no_init указывает компилятору не инициализировать переменную в области SRAM, а __persistent - во FRAM области. Инициализируем счетчик, отключаем вачдог и переводим пин со светодиодом (для визуального наблюдения) на выход и обнуляем регистр вывода: uint16_t count = 0; WDTCTL = WDTPW + WDTHOLD; P1DIR |= BIT0; P1OUT = 0; Далее идет очень хитрая штука. Называется она регистр PM5CTL0. В этом регистре есть бит LOCKLPM5, назначение которого блокировать регистры порта ввода-вывода. А такое необходимо, т.к. выход из режимов x.5 возможен только через ресет. По умолчанию этот бит установлен и вся работа с пинами заблокирована. Чтобы разблокировать, необходимо в него записать 0: PM5CTL0 &= ~LOCKLPM5; Дальше пишем цикл: while (1) { if (EEPROM[Write_Size - 1] == Write_Size - 1) { P1OUT |= BIT0; } else { SYSCFG0 = FRWPPW; for (uint16_t i = 0; i < Write_Size; i++) { EEPROM[i] = count++; } SYSCFG0 = FRWPPW | PFWP; } } Если в последнем элементе массива ожидаемое значение, то загорается светодиод, если нет, то уходим в подпрограмму записи элементов массива. Но прежде, чем его писать, необходимо разрешить запись в область FRAM памяти. Это делается с помощью записи разрешающей сигнатуры, которая определена в константе FRWPPW, в регистр SYSCFG0. По окончании записи и для защиты FRAM памяти от перезаписи необходимо поднять бит PFWP. В заголовочном файле вся эта кухня записана так: /* SYSCFG0 Control Bits */ #define PFWP_L (0x0001u) /* Program FRAM Write Protection */ #define DFWP_L (0x0002u) /* Data FRAM Write Protection */ #define FRWPPW (0xA500u) /* FRAM protection password */ Запускаем IAR, прошиваемся. Передергиваем питание и снова заходим в дебаггер с помощью кнопочки Запускаем окно Symbolic Memory, где переходим по адресу 0хС400 (можно подсмотреть в окне Watch по начальному адресу массива) или с помощью меню выбираем FRAM. Листаем область памяти до конца и видим такую картину Все наши 8000 байт записаны и лежат в недрах МК. Enjoy!
-
Здравствуйте! Прошу помощи ! Столкнулся со следующей проблемой пытаюсь подключить к контроллеру по spi память FRAM FM25CL64 ,компилятор keil , пытаюсь записать одно число и его же считать, а осциллографом вижу, что считывается не то, что записывал. Пытался в разные ячейки памяти разные числа - считываются разные числа, но не те. Пишу 0x2F считывается 0x1С, пишу 0xFF считывается 0xFE, пишу 0x99 считывается 0x20 - ерунда какая то. Куски кода привел ниже: int main(void) { SystemCoreClockUpdate(); SysTick_Config(SystemCoreClock/1000);//1ms LEDs_ini(); Button_ini(); SPI3_FRAM_ini(); delay_ms(50); //проверим FRAM начало запись 1 байта CS_FRAM_ON();// while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){}; SPI_I2S_SendData(SPI3, 0x06);//Set Write Enable Latch 6 while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется CS_FRAM_OFF(); delay_us(3); //на самом деле задержка выходит около 500нс CS_FRAM_ON(); while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){}; SPI_I2S_SendData(SPI3, 0x02);// Write while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x10);// 13 битный адрес while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x00);// 13 битный адрес while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x2F);// данные while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется CS_FRAM_OFF(); delay_us(3);//на самом деле задержка выходит около 500нс //проверим FRAM конец запись 1 байта //проверим FRAM начало чтение 1 байта CS_FRAM_ON();// while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){}; SPI_I2S_SendData(SPI3, 0x03);// Read while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x10);// 13 битный адрес while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x00);// 13 битный адрес while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется SPI_I2S_SendData(SPI3, 0x00);// пишем 0 для считывания while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE)== RESET){}; while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY)== SET){};//ждем пока запишется CS_FRAM_OFF(); //проверим FRAM конец чтение 1 байта //LED1_OFF; while(1) { настройки spi: SPI_Init_user3.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_Init_user3.SPI_Mode = SPI_Mode_Master; SPI_Init_user3.SPI_DataSize = SPI_DataSize_8b; SPI_Init_user3.SPI_CPOL = SPI_CPOL_High;//SPI_CPOL_Low SPI_Init_user3.SPI_CPHA = SPI_CPHA_2Edge; SPI_Init_user3.SPI_NSS = SPI_NSS_Soft; SPI_Init_user3.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//4 SPI_Init_user3.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init_user3.SPI_CRCPolynomial = 7; SPI_Init(SPI3, &SPI_Init_user3); контакты вроде все пересмотрел, думал провода может длинноваты, клок spi настраивал на разную частоту уменьшал до 1МГц - не влияет, пробовал делать паузу между командой WREN и командой записи 15мс, а записью и считыванием 20мс, всё то же самое не помогло.. приложил осциллограммы: Осциллограмма всех посылок WREN, WITE, READ (тактовый сигнал ch1 и miso FRAM ch2) (синий луч отношения к делу не имеет) Осциллограмма команды WREN (тактовый сигнал ch1 и miso FRAM ch2)(синий луч отношения к делу не имеет) Осциллограмма команды WITE (тактовый сигнал ch1 и miso FRAM ch2) Осциллограмма считанного значения записывал 0x2F, считал 0x1C (тактовый сигнал ch1 и mosi FRAM ch2)