буфер по умолчанию в библиотеке wire
- Войдите на сайт для отправки комментариев
В библиотеке wire буфер выставлен 32 байта. Но при попытке записать массив в 32 байта во внешнюю i2c eeprom - т.е. всю страницу записать пытаюсь (у меня сейчас AT24C32 - судя по datasheet там можно сразу страницами по 32 байта записывать) - из 32 байт пишется 30. Делаю так:
#include <Wire.h> #define memAdr 0x50 void setup() { Wire.begin(); Serial.begin(9600); byte dat[32]; for(byte i=0;i<32;i++){ dat[i]=110-i; } Wire.beginTransmission(memAdr); Wire.write(0); // Hba Wire.write(0); // Lba Wire.write(dat,32); Wire.endTransmission(); delay(20); }
Посмотрел код библиотеки - там функциями write в буфер загонятеся (int)адрес ячейки памяти (как раз те самые не достающие 2 байта), а потом данные. Это у меня библиотека кривая, или так и должно быть и я что-то не понимаю? Код из библиотеки:
// must be called in: // slave tx event callback // or after beginTransmission(address) size_t TwoWire::write(uint8_t data) { if(transmitting){ // in master transmitter mode // don't bother if buffer is full if(txBufferLength >= BUFFER_LENGTH){ setWriteError(); return 0; } // put byte in tx buffer txBuffer[txBufferIndex] = data; ++txBufferIndex; // update amount in buffer txBufferLength = txBufferIndex; }else{ // in slave send mode // reply to master twi_transmit(&data, 1); } return 1; } // must be called in: // slave tx event callback // or after beginTransmission(address) size_t TwoWire::write(const uint8_t *data, size_t quantity) { if(transmitting){ // in master transmitter mode for(size_t i = 0; i < quantity; ++i){ write(data[i]); } }else{ // in slave send mode // reply to master twi_transmit(data, quantity); } return quantity; }
Вобщем, кто уже с этим боролся? Я пока увеличил буфер в TWI и в WIRE, но это какое-то кривое решение - малоли как другие библиотеки использующие I2C эти константы используют... Можно, конечно, напрямую из TWI функции подергать... Но тогда уж проще под себя пилить, под конкретную задачу. А хочется готовой универсальности :)
Что-то мне подсказывает, что буфер в себя включает в том числе адрес. Двухбайтный.
Что-то мне подсказывает, что буфер в себя включает в том числе адрес. Двухбайтный.
Спасибо, Кэп! Некст тайм читаем плз дальше первых двух строк :)
На здоровье.
Нет, либа не кривая. С чего бы ей быть кривой? Просто создатели выставили размер буфера в 32 байта.
Если что-то непонятно - обратитесь к спецификациям интерфейса, узнайте, что и как, как передача происходит и прочее.
"Теперь ваша душенька довольна?"©
Очередное спасибо, Кэп! :) Каюсь, наизусть спецификацию не расскажу, так сказать по верхам прочитал. Но готов поспорить, что ограничения в 30 байт данных там нет :) И потому душа моя болит :)
Я перефразирую вопрос. Просто увеличив буфера... о как :) я кроме как на расход памяти вроде как ни на что не влияю. Кто-то же внешнюю eeprom использовал совместно с другими i2c? Или все побайтово пишут в память? Пока у меня ощущение, что 32 выбрано как в анекдоте, про то как считают программисты - 34 "нечетное" :)
Просто создатели выставили размер буфера в 32 байта.
Нет никакого ограничения. Что по кайфу, то и делайте с размером буфера.
Ты чего хотел-то? На этих строчках последние два байта из переданных тобой как байты данных и обрежутся. Буфер в Wire общий для адреса и для данных, так что - как есть: максимум, что ты сможешь передать - это 30 байт данных. Все вызовы write - это просто запись во внутренний буфер (ну да ты знаешь, раз код смотрел), актуальная передача - по endTransmission, такой вот механизм избран.
Так что выход один - увеличивать буфер, других вариантов не видно.
З.Ы. Ты ещё не видел косяков в стандартной либе Ethernet - там вообще прямо в комментарии сказано, что код не работает так, как надо :)))) Я уже привык :)
Уважаемые, а какой теоретически-возможный предел размера буфера Wire?
Очевидно, он может превышать размер оперативной памяти.
Очевидно, он может превышать размер оперативной памяти.
Это понятно. Но так-же очевидно, что разраб установил такой дефолтный предел не потому, что дальше 31 считать не умел. Был же какой-то смысл в этом ограничении?
Надо спросить у Nicholas Zambetti. Может у него номер дома - 32,
Это понятно. Но так-же очевидно, что разраб установил такой дефолтный предел не потому, что дальше 31 считать не умел. Был же какой-то смысл в этом ограничении?
Вообще-то при объеме памяти контроллера 2к экономить приходится каждый байт. Очевидно, что если при подключении Wire памяти больше не останется, это никого не устроит. Поэтому 32 байта - результат компромисса. В принципе, посмотрите тип переменных, которыми описывается дина/заполнение буфера. Если они двухбайтовые, то скорее всего, единственное ограничение указано в сообщении №8.
Вообще-то при объеме памяти контроллера 2к экономить приходится каждый байт. Очевидно, что если при подключении Wire памяти больше не останется, это никого не устроит. Поэтому 32 байта - результат компромисса. В принципе, посмотрите тип переменных, которыми описывается дина/заполнение буфера. Если они двухбайтовые, то скорее всего, единственное ограничение указано в сообщении №8.
Да, спасибо, уже вроде теоретически разобрался с этим вопросом. На ЕСП проблема дефицита SRAM не так остро стоит, как на AVR. Но в любом случае, мне под мои задачи восьмибитной длины буфера хватит. Завтра потестирую с AT24C32 на ds3231.
В библиотеке wire буфер выставлен 32 байта. Но при попытке записать массив в 32 байта во внешнюю i2c eeprom - т.е. всю страницу записать пытаюсь (у меня сейчас AT24C32 - судя по datasheet там можно сразу страницами по 32 байта записывать) - из 32 байт пишется 30. ...
Вобщем, кто уже с этим боролся? Я пока увеличил буфер в TWI и в WIRE, но это какое-то кривое решение - малоли как другие библиотеки использующие I2C эти константы используют...
Вы сами себе создали проблему , и теперь героически пытаетесь ее решить. Я буквально вчера писал библиотеку для ЕЕПРОМки у которой страница 64 байта, и никаких трудностей не встретил.
По умолчанию
а завтра ты поставишь новую версию IDE, забудешь про свои правки и будешь до крови мучительно долго чесать плешь на затылке, не понимая, что произошло, "ведь токашто всё работало". Ситуация усугубится еще и тем, что, накатив опять старую рабочую версию IDE, ошибки не уйдут, ибо ты просто затёр все свои исправления. Останется только искать по хозяйственным крепкую табуретку и скользкое ароматное мыло.
Я буквально вчера писал библиотеку для ЕЕПРОМки у которой страница 64 байта, и никаких трудностей не встретил.
твой код нерабочий при len>30.
Особенно порадовала строчка cs |= b
на случайных данных, ты в 99% случаев будешь возвращать число, близкое или равное 0xFF.
если это должна быть типа контрольная сумма (чего?) то решение не просто неудачное, а феерический facepalm.
твой код нерабочий при len>30.
Вообще-то вчерась успешно таким образом писал куски по 68 байт. Специально брал больше страницы, чтоб проверить работу нескольких обращений к данной фукции.
Но скорее всего у Вас есть аргументы. :)
Особенно порадовала строчка cs |= b
на случайных данных, ты в 99% случаев будешь возвращать число, близкое или равное 0xFF.
если это должна быть типа контрольная сумма (чего?) то решение не просто неудачное, а феерический facepalm.
ага, чушь написал.
Вообще-то вчерась успешно таким образом писал куски по 68 байт.
Какие ваши доказательства?
а завтра ты поставишь новую версию IDE, забудешь про свои правки и будешь до крови мучительно долго чесать плешь на затылке, не понимая, что произошло, "ведь токашто всё работало".
Если это мне, то 128 стоит по умолчанию в Wire.h из СДК ESP32 версии 1.0.4. Я ничего не правлю в чужих библиотеках ))
Так, мне кажется более универсально было бы
ну, если речь за ESP32, тада я беру всё сказанное взат.
На гите есть библа для FRAM. Пример порадовал 8-D
Какие ваши доказательства?
Вот мой черновик, я сначала добился чтоб работал этот код.
В монитор выдается:
Я сделал вывод что код рабочий. В проекте он тоже заработал так, как я предполагал.
Кстати, вот этот кусок :
Я сначала написал так: uint8_t pages = len/PAGE_SIZE + (len%PAGE_SIZE)? 1:0;
Но чей-то условие не работало. Что не так?
если это код для STM, то вполне вероятно, что он работает как надо. Моё замечание касается AVR
А это передайте громадный привет создателям С с их неявными (и не очевидными) приоритетами операций, ваш код будет исполняться, как (len / PAGE_SIZE + (len % PAGE_SIZE)) ? 1:0 с очевидным результатом 1 либо 0 :)
Очевидное решение - поставить скобки len / PAGE_SIZE + ((len % PAGE_SIZE) ? 1:0, но, к счастью, есть более правильное решение (len + PAGE_SIZE - 1) / PAGE_SIZE.
есть более правильное решение (len + PAGE_SIZE - 1) / PAGE_SIZE.
Так, мне кажется более универсально было бы
Набросал класс для записи/чтения любых объектов (пока кроме литералов) любых размеров в i2c EEPROM. Пока физически в наличии только ат24с32. На днях проверю с ат24с256 (там другой размер страницы). Пока не понимаю, как реализовать автоопределение, поэтому выбор через соответствующий дефайн. Работает на ESP32 с I2C_BUFFER_LENGTH 128. По идее должна и с 32 нормально работать на AVR.
Корифеи, если не лень, потыкайте пожалуйста в ошибки
Результат
Если я правильно помню, в eeprom размер страницы зависит от объёма и прописан в дпташитах, введите define в скетче с объёмом и от него считайте.
Ну так ровно это сейчас уже и сделано.
В строке 95 ошибка. должно быть
Да, с этим нужно что-то делать
Пока не понимаю, как реализовать автоопределение, поэтому выбор через соответствующий дефайн.
Да, с этим нужно что-то делать
чтобы формально соблюсти Пухово бестолковое правило, укажи вручную, какие ненужные конструкторы неявно создавать НЕ надо. И какие надо тоже укажи.
чтобы формально соблюсти Пухово бестолковое правило, укажи вручную, какие ненужные конструкторы неявно создавать НЕ надо. И какие надо тоже укажи.
Если честно, я не уверен, что кроме конструктора инициализации тут что-то еще может быть востребовано. Даже роль деструктора в данном классе и реальных сценариях применения мне не совсем очевидна. Но, для формального следования правилам можно сделать. Потом))
Кстати, добавил работу с литералами. Если кому интересно, могу выложить.
На днях должны приплыть fm24cl64. Там нет страниц и не требуется 5 миллис для внутричиповых процедур записи. Вот красота то будет
Пока не понимаю, как реализовать автоопределение, поэтому выбор через соответствующий дефайн.
Автоопределение реализуемо. За одну команду записи не может записатся больше одной страницы. Даже если передано больше. Через это св-во делать.
За одну команду записи не может записатся больше одной страницы. Даже если передано больше.
а как eeprom должен сигнализировать записалось или нет?
Автоопределение реализуемо. За одну команду записи не может записатся больше одной страницы. Даже если передано больше. Через это св-во делать.
В принципе, можно записать uint16_t в 0x1F и попытаться прочитать. Если успех - значит 128 или 256. А вот как определить полный объем чипа? Он и пишет и читает кольцом
m должен сигнализировать записалось или нет?
С еепром главный вопрос не это, а КУДА записалось
Автоопределение реализуемо. За одну команду записи не может записатся больше одной страницы. Даже если передано больше. Через это св-во делать.
В принципе, можно записать uint16_t в 0x1F и попытаться прочитать. Если успех - значит 128 или 256.
да. пишем допустим 1КБ неспеша нулями. Потом одной командой пытаемся записать 1КБ 0х01. Читаем сколько реально прописалось - это страница
А вот как определить полный объем чипа? Он и пишет и читает кольцом
тоже просто. Пишем по адресу 0 допустим 0х00. Далее через 1КБ (или 2КБ, какой минимальный обем на подозрении в общем) пишем допустим 0х01. После каждого раза проверяем адрес 0. Если уже не 0 а 0х01 - пошли по кругу
все это конечно реально, и опытным путем да, определить наверное можно и размер страницы и чипа, только возникает одна проблема - если в EEPROM уже есть нужные данные, затирать их экспериментом очень не хочется. Так что надежнее изначально говорить программе что мы втыкаем в устройство.
да. пишем допустим 1КБ неспеша нулями. Потом одной командой пытаемся записать 1КБ 0х01. Читаем сколько реально прописалось - это страница
А вот как определить полный объем чипа? Он и пишет и читает кольцом
тоже просто. Пишем по адресу 0 допустим 0х00. Далее через 1КБ (или 2КБ, какой минимальный обем на подозрении в общем) пишем допустим 0х01. После каждого раза проверяем адрес 0. Если уже не 0 а 0х01 - пошли по кругу
1. Писать страницами не вариант. Там же что-то уже записано может быть. Определение размера страницы легко записью одного int-а >255 определить. Если на 0х1F страница заканчивается, то запись произойдет в 0x1f 0x00. А прочитается из 0x1f 0x20.
2. Хороший вариант. Попробую.
Все что в памяти было - прощаю ;)
Проблема определения параметров еепрома актуальна при первом запуске или после перепайки еепрома. В обоих случаях содержимое не валидно. После определения найденные значения сохраняем в энергонезависимой памяти, на следующих ребутах берем оттуда. Я когда ФС писал, то по команде форматирования это делал. Сохранял в нулевую страницу, вместе с всякой всячиной типа смещения страницы, содержащей начало таблицы файлов и т.д. По этим данным считал хеш, потом его же тоже сохранял в нулевой странице. При ребуте проверял хеш, если ОК - все параметры валидны, если не ОК - форматируем.
Проблема определения параметров еепрома актуальна при первом запуске или после перепайки еепрома.
Если паяешь в достаточно трезвом виде, до эта задача представляет сугубо академический интерес
Сделал, посмотрите, если не трудно ))
Функция:
Все целиком:
Про еепром и ребуты не додумал, ага
В первом фрагменте строка 9 что делает?
Спасибо, не выспался сегодня(( Поправил
Пока не наблюдаю исправлений. sizeof не возвращает размер массива в айтемах, он работает с байтами. А в Вашем массиве двубайтовые айтемы. Поставьте println(i), посмотрите до скольки досчитает.
да я знаю, затупил просто. У себя уже поправил. Через пару часов обновлю тут. С телефона не очень. Поделил на размер элемента, как дОлжно
for
(uint8_t i = 0; i<
sizeof(sz)/
sizeof
(sz[0])
Вроде похоже.