Побайтово чтение с SD

Kakmyc
Offline
Зарегистрирован: 15.01.2018

О, великие и могучие ГУРУ.
Научите оленя.
На карте лежит бинарник, его надо считать побайтово.
Мануалы курил(может плохо),
Какими функциями это реализовать ?
Типа

File myFile;
myFile=SD.open("BIN");
Byte=myFile(номер байта)????
Или как то так.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

На парсер памяти нет и процессорного времени нет.
Я же правильно понимаю, что
командой
myFile=SD.read("bin");
Создаётся буфер в 512байт ?
Как с ним работать ?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Не знаю, чего ты там накурился и откуда взял read("bin");, но простой read(); спокойно читает один байт.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Да , херню написал.
Следовало.
myFile=SD.open("bin");

Далее вроде как разобрался:
myFile.seek(num);
myByte=myFile.peek();
Слишком сложно так для каждого байта.
Или можно как то проще ?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

В общем задача, с карты памяти выводить бмпшки на экран.
Библиотеки(графика+СД) сжирают 90% оперативы.
Ну и фиг с ним главное разобраться.
Потом буду смотреть в сторону spiflash

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:
Далее вроде как разобрался: myFile.seek(num); myByte=myFile.peek(); Слишком сложно так для каждого байта. Или можно как то проще ?

ну так ты же хотел побайтно читать? - "побайтно" - это по одному байту. что не так?

Если хочешь быстрее, читай описание библиотеки SD. например функция read может читать из файла блоками.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Kakmyc пишет:
Далее вроде как разобрался: myFile.seek(num); myByte=myFile.peek();

Ты уверен, что разобрался. Что точно знаешь, что тебе надо именно peek, а не read? Разницу между ними понимаешь?

sadman41
Offline
Зарегистрирован: 19.10.2016

peek() - экономная команда, не разбазаривает байтики почем зря...

Kakmyc
Offline
Зарегистрирован: 15.01.2018

У меня в цикле for эта связка.

myFile=SD.open("BMP.bin",FILE_READ);
	uint16_t bit;
	uint8_t data;
     
	for(int cy=0;cy<sy;cy++){
	for(int cx=0;cx<sx;cx++){
		bit=7-(cx%8);
           myFile.seek((cy*(sx/8)+(cx/8)));
		data=myFile.read();
         
	if ((data & (1<<bit))>0)
				myOLED.setPixel(x+cx, y+cy);
			else
				myOLED.clrPixel(x+cx, y+cy);

Так , что думаю без разницы, peek() или read()

sadman41
Offline
Зарегистрирован: 19.10.2016

А, ну правильно. Если нет разницы, то peek() гораздо лучше смотрится рядом с seek(). Рифма и всё такое.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

sadman41 пишет:

А, ну правильно. Если нет разницы, то peek() гораздо лучше смотрится рядом с seek(). Рифма и всё такое.

Может за место стеба, что то дельное напишешь ?

sadman41
Offline
Зарегистрирован: 19.10.2016

Kakmyc пишет:

Может за место стеба, что то дельное напишешь ?

Например?

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Может за место стеба, что то дельное напишешь ?

может ты вместо хамства все же посмотришь в учебнике, в чем разница read() и peek()?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

b707 пишет:

Kakmyc пишет:

Может за место стеба, что то дельное напишешь ?

может ты вместо хамства все же посмотришь в учебнике, в чем разница read() и peek()?

Ну я посмотрел.

Отличия в том, что read() считывает баит и сдвигается на следующий.

А peek() считывает и не сдвигается.

Учитывая, что я явно читаю байт по конкретному адресу, что меняется ?

Может я учебник, взял херовый ?

По делу то в состоянии кто нибудь ответить ?

И в чем заключается хамство ?

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Отличия в том, что read() считывает баит и сдвигается на следующий.

А peek() считывает и не сдвигается.

Учитывая, что я явно читаю байт по конкретному адресу, что меняется ?

фигово у тебя с логикой. В своем коде ты в цикле считываешь кучу байт подряд. Если взять read() вместо peek() - seek() на каждом шаге становится лишним.

А если наморщить лоб дальше - можно вместо двух циклов считывать весь блок байт одним действием.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

b707 пишет:

Kakmyc пишет:

Отличия в том, что read() считывает баит и сдвигается на следующий.

А peek() считывает и не сдвигается.

Учитывая, что я явно читаю байт по конкретному адресу, что меняется ?

фигово у тебя с логикой. В своем коде ты в цикле считываешь кучу байт подряд. Если взять read() вместо peek() - seek() на каждом шаге становится лишним.

А если наморщить лоб дальше - можно вместо двух циклов считывать весь блок байт одним действием.

А если ещё наморщить лоб и внимательно прочитать условия, то тогда становится понятно, что весь блок не куда пихать.

У меня свободных ОЗУ 100 байт, а блок 512.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

У меня свободных ОЗУ 100 байт, а блок 512.

с чего это блок именно 512? - можно читать блок произвольного размера - тот, который тебе нужен.

Кроме того, если я правильно понял код выше - для извлечения каждого бита ты 8 раз подряд читаешь один и тот же байт. При таком стиле никакой памяти не хватит

Kakmyc
Offline
Зарегистрирован: 15.01.2018

А что это как то на память влияет ?

Количество переменных не меняется вроде.

Процессорное время кушает, это да.

По другому как реализовать , так и не придумал.

Ещё один цикл for вкладывать, дак он точно от ОЗУ кусок откусит.

Если я читаю блок, этот блок нужно тоже хранить где то.

И потом точно так же из него выгрызать байты нужные.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

По другому как реализовать , так и не придумал.

а если вставить чтение байта между двумя For? - первым циклом читаем байт, вторым перебираем биты.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Ну нет готовой библиотеки которая может с карты битмапы читать и выводить на ssd1306.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Ну нет готовой библиотеки которая может с карты битмапы читать и выводить на ssd1306.

при чем тут это? какое это имеет отношение к тому. что вы два цикла неправильно написали?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

b707 пишет:

Kakmyc пишет:

По другому как реализовать , так и не придумал.

а если вставить чтение байта между двумя For? - первым циклом читаем байт, вторым перебираем биты.

Нет, нельзя.

В строке может быть произвольное количество байт.

Первым циклом я перебираю строки, вторым столбцы.

Придется вводить , либо переменную, либо опять же считать момент , когда на следующий байт переходить.

Я сделал, расчет номера байта по координатам.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

В функцию передаются, координаты картинки х,у

Ее размеры sx,sy.

А дальше построчно рассчитывается состояние каждого пикселя.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Kakmyc пишет:

У меня в цикле for эта связка.

myFile=SD.open("BMP.bin",FILE_READ);
	uint16_t bit;
	uint8_t data;
     
	for(int cy=0;cy<sy;cy++){
	for(int cx=0;cx<sx;cx++){
		bit=7-(cx%8);
           myFile.seek((cy*(sx/8)+(cx/8)));
		data=myFile.read();
         
	if ((data & (1<<bit))>0)
				myOLED.setPixel(x+cx, y+cy);
			else
				myOLED.clrPixel(x+cx, y+cy);

Так , что думаю без разницы, peek() или read()

тяжелый случай, зачем каждый пиксель то рисовать.

берете пример из любой библиотеки работы с oled

там вполне себе примитивно выводится одной командой содержимое графического файла

void OzOLED::drawBitmap(const byte *bitmaparray, byte X, byte Y, byte width, byte height){
// max width = 16
// max height = 8
	setCursorXY( X, Y );
	byte column = 0; 
	for(int i=0; i<width*8*height; i++) {  
		sendData(pgm_read_byte(&bitmaparray[i]));
		if(++column == width*8) {
			column = 0;
			setCursorXY( X, ++Y );
		} 
	}
}

т.е. никакого цикла по байту нафиг не надо, считали байт из файла и его  же сразу вывели

sendData(

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Научите, как битмап с карты памяти читать ?

Без парсинга только, а то памяти нет от слова совсем.

И желательно не с фиксированным 16х8 размером, а произвольным.

И да в вашем примере считать ничего не нужно в принципе.

Все размерами ограниченно.

Только вот придется большие картинки на кучу паззлов делить и потом собирать.

 

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

И да в вашем примере считать ничего не нужно в принципе.

Все размерами ограниченно.

 

что там ограничено? Вы в коде разберитесь - там картинка точно так же последовательно читается побайтно. вся разница - что там чтение из массива, а у вас из файла на карте

Kakmyc
Offline
Зарегистрирован: 15.01.2018

andycat пишет:

Kakmyc пишет:

У меня в цикле for эта связка.

myFile=SD.open("BMP.bin",FILE_READ);
	uint16_t bit;
	uint8_t data;
     
	for(int cy=0;cy<sy;cy++){
	for(int cx=0;cx<sx;cx++){
		bit=7-(cx%8);
           myFile.seek((cy*(sx/8)+(cx/8)));
		data=myFile.read();
         
	if ((data & (1<<bit))>0)
				myOLED.setPixel(x+cx, y+cy);
			else
				myOLED.clrPixel(x+cx, y+cy);

Так , что думаю без разницы, peek() или read()

тяжелый случай, зачем каждый пиксель то рисовать.

берете пример из любой библиотеки работы с oled

там вполне себе примитивно выводится одной командой содержимое графического файла

void OzOLED::drawBitmap(const byte *bitmaparray, byte X, byte Y, byte width, byte height){
// max width = 16
// max height = 8
	setCursorXY( X, Y );
	byte column = 0; 
	for(int i=0; i<width*8*height; i++) {  
		sendData(pgm_read_byte(&bitmaparray[i]));
		if(++column == width*8) {
			column = 0;
			setCursorXY( X, ++Y );
		} 
	}
}

т.е. никакого цикла по байту нафиг не надо, считали байт из файла и его  же сразу вывели

sendData(

 

В качестве примера вам код того же самого от adafruit

void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = bitmap[j * byteWidth + i / 8];
            writePixel(x+i, y, (byte & 0x80) ? color : bg);
        }
    }
    endWrite();
}

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Но тут опять же, как и в вашем примере, с массива идёт чтение.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Но тут опять же, как и в вашем примере, с массива идёт чтение.

а есть разница? - файл битмапа - этот тот же массив. Смещение байта в  файле - все равно что индекс в массиве.

разница между кодом Адафруита и Андиката в том, что у него байты по вертикали (как и в экране), а у Адафруита по горизонтали.

Поэтому первый вопрос - как идут байты у вас в файле? Судя по вашему коду - видимо как у Адафруита. тогда выгоднее читать сразу по 8 байт. расположенных друг под другом (8*8 пикселей) -а потом разом выводить

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

.del

Kakmyc
Offline
Зарегистрирован: 15.01.2018

В том то и дело, что ему не надо знать положение курсора в двух координатах массива, ТК она у него одна.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

В том то и дело, что ему не надо знать положение курсора в двух координатах массива, ТК она у него одна.

Да неужели? думаете, у него все битмапы - в ниточку 1 пиксель? :) Точно так же там есть координата по х и кордината по у.

Можно и с другой стороны посмотреть - можно сказать, у вас в файле тоже только одна координата - смещение байта.

Резюме -чтение их массива и чтение из файла - операции, похожие как близнецы.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

По смыслу да, а вот по исполнению не очень.

Одно дело , когда то что надо уже в памяти, и совсем другое, когда это в память надо как то засунуть . и

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Kakmyc пишет:

По смыслу да, а вот по исполнению не очень.

Одно дело , когда то что надо уже в памяти, и совсем другое, когда это в память надо как то засунуть . и

 

вы наверное не поняли, если в память и надо что то засовывать, то исключительно за один цикл сразу несколько байт.

например у вас в файле на карте лежат такие числа

1 2 4 8 16 16 16 255 1 2 4 8 16 16 16 255 1 2 4 8 16 16 16 255  и т.д. Если это все перевести в картинку то получится наклонная линии потом горизонтальная линия потом вертикальная линия в воображаемых квадратиках 8 на 8 пикселей.

Теперь вам необходимо вывести его на oled дисплей, но там растр изображения идет построчно по например 8 символов, но каждые 8 байт  в символе идут растр сверху вниз.

т.е. мы считываем 8 байт, сразу же при чтении в этом же цикле, отбираем сначала нулевые потом первые и т.д биты в новые байты.

после получения новых 8и байт уже перевернутых

1 1 1 15 17 33 65 129 (если не понятно - на бумажке матрицу 8 на 8 нарисуте и все поймете)

в цикле их выводим в oled дисплей

читаем следующие 8 байт из файла и так по кругу пока файл не закончиться или дисплей не заполниться - в зависимости от задачи.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

я когда экспериментировал со своим странным модулем oled, я тупо в память его записывал разные числа с паузой в треть секунды и смотрел что он и как отображает, сразу вырисовывается как у него организована структура памяти.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

У меня свободных 121 байт, программа перестает работать, если пытаюсь монитор для отладки включить. А вы мне предлагаете ещё переменных туда напихать, формул, циклов и массив ещё один.
Он мне там даже на 8байт не нужен.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Была бы мега2560.
Читал бы сразу всю картинку в массив , а потом выводил бы стандартным drawBitmap.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

А покажите весь скетч :)
Я почти уверен что можно много выкинуть.
Помниться на финише одного проекта в этом году я сократил память с 91 % до 39 %.
Безвыходных ситуаций не бывает.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Похоже, медицина бессильна, хльт показывай скетч, хоть нет.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Современные веянья : вместо того чтоб включить мозг для оптимизации ПО, покупают новый более мощный МК.
ЗЫ. Помниться тут ЕвгенийП скидывал табличку сравнения современных МК и тех кто спутниками управляют.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:
У меня свободных 121 байт, программа перестает работать, если пытаюсь монитор для отладки включить. А вы мне предлагаете ещё переменных туда напихать, формул, циклов и массив ещё один. Он мне там даже на 8байт не нужен.

Кактус, хватит ныть про память. Память надо экономить не говнокодом, который пиксели по отдельности отрисовывает, а разумным проектированием программы. Уверен, что у тебя можно выиграть в программе кучу места. Начать с того, какую библиотеку для Sd ты используешь - например SD.h самая крутая. но и самая прожорливая, SDFat.h - попроще и поэкономнее, а еще есть специальные моды для малой памяти типа SDMini... - разница в расходе памяти может достигнуть 500 байт.

Во вторых - все ли текстовые строки запихнуты во флеш? Константы - обьявлены константами? Размер переменных оптимизирован?

В третьих - зайдем с глобальной стороны. А нужна ли тебе вообще SDкарта? Если ты с нее только битмапы грузишь - может их во флеш загрузить? какого размера битмапы?

ну и в четвертых - а битмапы вообще нужны? основной смысл программы в чем? если это какая-то автоматика с датчиками, то битмапы - это бесполезные "бантики", от которых нужно отказаться в пользу простого текстового интерфейса...

Kakmyc
Offline
Зарегистрирован: 15.01.2018
#include <OLED_I2C.h>
#include <SPI.h>
#include <SD.h>

OLED  myOLED(SDA, SCL, 8);
File myFile;

void setup()
{
      Serial.begin(9600);
    SD.begin(4);
   
   myOLED.begin();    
    myOLED.clrScr();
}

    void loop()
{
drawBitmap(10, 0, "img1.bmp", 64, 64);
   myOLED.update();
    
}

void drawBitmap(uint8_t x, uint8_t y,String bitmap,uint8_t sx, uint8_t sy)
{
 myFile=SD.open(bitmap);
	uint8_t bit;
	uint8_t data;
     	for(int cy=0;cy<sy;cy++){
	for(int cx=0;cx<sx;cx++){
		bit=7-(cx%8);
          myFile.seek((cy*(sx/8)+(cx/8)));
		data=myFile.peek();
          
	if ((data & (1<<bit))>0)
				myOLED.setPixel(x+cx, y+cy);
			else
				myOLED.clrPixel(x+cx, y+cy);           
}
}
    myFile.close();
    }

Вот весь скетч

Буду рад, если получится отсюда что нибудь выкинуть без кастрации библиотек. Т.к. сами библиотеки оставляют 193 байта ОЗУ.

Ну монитор разве что убрать.

Что касается библиотеки SD , тут ввиду непонятного формата используемых карт вариантов нет.

Была бы уверенность в том, какая конкретно карта с какой конкретно файловой системой, можно было бы без библиотеки обойтись.

b707
Offline
Зарегистрирован: 26.05.2017

можно поинтересоваться смыслом проекта? Читать любые битмапы с любых карт и выводить на крохотный экран? А что дальше -  если 42 строчки кода уже заняли всю доступную память?

Может все-таки можно выбрать какие-то определенные картинки и заранее загрузить их в ардуину. чтобы отказаться от СД-карточек вовсе?

Кроме того, библиотеки OLED тоже есть разные. Не знаю, что там в вашей, но во многих буфер во весь экран размером... Но есть и другие - совсем без буфера.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

andycat пишет:
Помниться тут ЕвгенийП скидывал табличку сравнения современных МК и тех кто спутниками управляют.
Да ладно, спутниками - там был пилотируемый космический корабль, который на Луну летал.

Kakmyc пишет:
Была бы мега2560.

А что Меги на али закончились? Если нет, то поставь.

А ещё лучше, с Архатом поговори. Он как-то там к Меге еще полвагона дополнительной памяти прицеплял. Будешь картинки с порносайтов показывать. Круто!

Kakmyc
Offline
Зарегистрирован: 15.01.2018

К сожалению хотелки не мои.

Да, только картинки буду показывать.

Но их количество перевалит за сотню, так что флеш не вариант.

В дальнейшем планируется перейти на SPIflash.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

К сожалению хотелки не мои.

Да, только картинки буду показывать. Но их количество перевалит за сотню, так что флеш не вариант.В дальнейшем планируется перейти на SPIflash.

"Хотелки не ваши" ? - хотите сказать, что вы это на заказ кодите?:)))

Если не хотите потрошить библиотеки, размер этого кода особо не уменьшить.  Возьмите другую плату - например BluePill от СТМ32 (шутка)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Kakmyc пишет:
Вот весь скетч

Жесть! 

Kakmyc пишет:

Т.к. сами библиотеки оставляют 193 байта ОЗУ.

Это кто ж тебе такое сказал? Плюнь ему в рожу! Открой файл OLED_I2C.h и посмотри на строку 132

uint8_t scrbuf[1024];

и объясни мне как программа с такой строкой может занимать 193 байта?

---------------

Значит так. Буфер экрана видишь? Так вот читай со своей карты ПРЯМО в этот буфер. И тогда тебе вообще не нужна никакая дполнительная память от слова совсем.

Чтобы понять как писать прямо в буфер посмотри как утсроена библиотечная функция

void OLED::setPixel(uint16_t x, uint16_t y)

и делай как она - пихай прочитанные байты прямо в буффер.

Ну или откажись от буфера, но это ты, боюсь, пока не сумеешь.

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Да в общем то уже все. 

Результат устроил работа закончена. 

 

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Да в общем то уже все. 

Результат устроил работа закончена. 

 

ну да, ну да... и скетч, который только и знает, что читает один и тот же байт 8 раз...

"Результат устроил" - я плачу...

Kakmyc
Offline
Зарегистрирован: 15.01.2018

to b707

Если выкинуть в скетче SD и SPI, а оставить только то , что относиться к OLED_I2C.

То используется 1064 байта ОЗУ, и с ваших слов там ещё буфер на 1кБ.

На весь скетч и обработчик библиотеки 40 байт ???

Ну,ну.

С буфером Adafruit_SSD1306.h.

Вот там уже голая библиотека 1,5кБ кушает.

Поэтому от нее пришлось отказаться в первую очередь.

Голая OLED_I2C , чуть больше 800 байт занимает. 

Какой там килобайтный буфер ?

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

На весь скетч и обработчик библиотеки 40 байт ???

Ну,ну.

А что там в скетче, если выкинуть SD, SPI и OLED?  НИЧЕГО! - код на уровне примера блинк. Смотрели, сколько памяти занимает блинк? - посмотрите. 9 байт.

Так что для вашего скетча 40 байт - это много.