@bwubs This is part of the arduino-esp32 package: https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi/src, you should have that installed already.
Posts made by murraypaul
-
RE: Spotify app for M5Paper
-
M5Paper end of life?
Just received the following notification from Digi-Key:
You have purchased the following part number from Digi-Key within the last two years. The manufacturer has announced an update to the part status.
Part Affected
Manufacturer M5STACK TECHNOLOGY CO., LTD
Description M5PAPER ESP32 DEV KIT 4.7"E-INK
Manufacturer Part Number K049
Digi-Key Part Number 2221-K049-ND
Status Obsolete
Substitutes Please click hereDigging around leads to: https://media.digikey.com/pdf/PCNs/M5Stack/PCN20210513-01.pdf
Which contains: "The display driver chipset for K049 cannot be purchased and supplier from our vendor any more. We will look for new display driver as the alternative material. This version will stop for sale. "
-
RE: [M5Paper] An EPub Reader using ESP-IDF
I have written a reader for simpler formats (plain text with a bit of markdowny style syntax), I didn't find the TFT_eSPI interface to be limiting, except in not being able to handle multiple TTF fonts, which I was able to solve.
I think you'd need to have a specific problem that the provided library didn't handle to take the hassle of trying to get something else working.
-
RE: Sudoku app for M5Paper
@felmue I've updated the code, it should now compile with no warnings in PlatformIO.
-
RE: Sudoku app for M5Paper
@felmue I'll try to get PlatformIO set up and take a look, thanks,
-
RE: Spotify app for M5Paper
@bwubs Just one, which you have to specify when compiling the app.
-
Sudoku app for M5Paper
Source available here: https://github.com/murraypaul/M5Sudoku
M5Sudoku
Sudoku application for M5Paper
Can generate uniquely solveable Sudoku puzzles, targetting a given number of clues, to act as a difficulty setting.
At any point, can validate that the puzzle is still solvable.
Can mark squares as either a known value, or a set of possible values.
Can save and reload current state to EEPROM.
Will automatically shutdown and save state after 5 minutes of inactivity.
Notes:
- Selecting a square in the large grid will display it in the small grid on the right
- The selected square is highlighted in the large grid
- You can use the small grid to either set a single known value for the square, or select multiple possible values
- It may not be possible to generate a uniquely solveable puzzle of the given numbers of clues in the time requested
- In this situation, the puzzle with the lowest number of clues that still gives a unqiue solution will be returned
- The fewer target clues you ask for, the longer it will take to generate the puzzle
- The 'Validate' button will confirm that the puzzle is still uniquely solveable
- The 'Clue' button will fill in one randon unsolved square
- Over time the screen may get a bit muddy, due to the fast refresh option used on the EPD screen
- The 'Validate' button will also do a full screen slow refresh, which will clean up the display
-
RE: M5Paper: Screenshot function
The most likely issue is that the filename you pass doesn't start with '/', which is required by the SD library.
To view the logging output, assuming you are using the Arduino UI, first do Tools->Core Debug Level->Set to Debug or Verbose. Then do Tools->Serial Monitor.
You will see debug output from the M5Paper appear in the serial monitor window. -
RE: Working with jpg images
I have a M5Paper, not a Core2, but the APIs look very similar.
You can use something like bin2header (https://github.com/AntumDeluge/bin2header) to convert your jpg file to a C header file and include that in your project. It will start with something like:static const unsigned char my_file_name_jpg[] = {...
You can then use the memory buffer form of drawJpg:
void drawJpg(const uint8_t *jpg_data, size_t jpg_len, uint16_t x = 0, uint16_t y = 0, uint16_t maxWidth = 0, uint16_t maxHeight = 0, uint16_t offX = 0, uint16_t offY = 0, jpeg_div_t scale = JPEG_DIV_NONE);
Like this:
drawJpg(my_file_name_jpg,sizeof(my_file_name_jpg),x,y,...)
(As the other poster said, this might not be the best way of doing it, but it is available.)
-
Spotify app for M5Paper
Application to monitor and control a Spotify client using the M5Paper.
Note: This is not itself a Spotify client, it cannot stream Spotify through the M5Paper.Three screen layouts available, show below.
Initial Spotify authentication through a built-on webserver, then refresh token saved to EEPROM and should function independently.Polls Spotify to update data at one of two compile-time configurable rates, depending on whether there is currently an active Spotify device found or not. Shuts down after configurable interval with no active client found if running on battery.
You need to create a (free) developer account and client app with Spotify, and approve access of this application to your Spotify account.
Requested scopes are:
- user-read-private
- user-read-currently-playing
- user-read-recently-played
- user-read-playback-state
- user-modify-playback-state
Code available at https://github.com/murraypaul/M5Spot.
Based on original M5Spot project by Cosmic Mac available at https://github.com/CosmicMac/M5Spot.Icons by icons8.
-
RE: M5Paper Canvas Rendering Artifacts
My question is, if the behavior is required or an artifact of the integration with the driver?
I think this is required.
When actually transferring data to the screen, this is done 4 pixels at a time.Shouldn't the library simply forbid creating a canvas that is not a multiple of 4?
Probably, yes.
-
M5Paper: Screenshot function
Someone had asked in another thread whether there was an easy way to take a screenshot of the M5Paper.
I've put together a function to do that.
It can take a screenshot in two formats. 16 colour (4bpp) BMP makes the most sense, as that is what the device can actually display, and only takes about 250KB, but full colour (24bpp) BMP is the format that the device can easily read back in again, and takes about 1.5MB.
This is recording what is stored in the canvas framebuffer, not what is actually displayed on the screen. They will be different if you have called drawing functions and not yet called pushCanvas, or if you are using multiple canvases.
Taking a full screen 24bpp screenshot is quite slow, taking about 10 seconds on my SD card.bool takeScreenshot( M5EPD_Canvas& canvas, String filename, bool bFull24bpp = true, int xPos = 0, int yPos = 0, int xSize = -1, int ySize = -1 ) { File bmpFile = SD.open(filename,FILE_WRITE); if( !bmpFile ) { log_e("Failed to open '%s' for write",filename); return false; } xSize = max( 1, min( xSize == -1 ? canvas.width() : xSize, canvas.width() - xPos ) ); ySize = max( 1, min( ySize == -1 ? canvas.height() : ySize, canvas.height() - yPos ) ); if( !bFull24bpp && xSize % 2 == 1 ) xSize++; log_d("Taking %d x %d screenshot to '%s'", xSize, ySize, filename); size_t bytes_written = 0; auto write8 = [&file=bmpFile,&bytes_written]( uint8_t data ) { bytes_written += file.write(data); }; auto write16 = [&file=bmpFile,&bytes_written]( uint16_t data ) { bytes_written += file.write(((uint8_t *)&data)[0]); bytes_written += file.write(((uint8_t *)&data)[1]); }; auto write32 = [&file=bmpFile,&bytes_written]( uint32_t data ) { bytes_written += file.write(((uint8_t *)&data)[0]); bytes_written += file.write(((uint8_t *)&data)[1]); bytes_written += file.write(((uint8_t *)&data)[2]); bytes_written += file.write(((uint8_t *)&data)[3]); }; auto writeN = [&file=bmpFile,&bytes_written]( uint8_t* data, size_t N ) { bytes_written += file.write(data,N); }; uint8_t bpp = bFull24bpp ? 24 : 4; size_t bmpHeaderSize = 14; size_t dibHeaderSize = 40; size_t colourTableSize = bpp == 24 ? 0 : pow(2,bpp)*4; size_t gap1Size = 2; size_t rowSize = ceil(bpp * xSize / 32.0) * 4; size_t rowGap = rowSize - (bpp * xSize / 32.0) * 4; size_t pixelArraySize = rowSize * ySize; size_t pixelArrayOffset = bmpHeaderSize + dibHeaderSize + colourTableSize + gap1Size; size_t expectedSize = pixelArrayOffset + pixelArraySize; // log_d("Expected size %d, row size %d, row gap %d, pixel array offset %d, pixel array size = %d",expectedSize, rowSize, rowGap, pixelArrayOffset, pixelArraySize); write16( 0x4D42 ); write32( expectedSize ); write32( 0 ); write32( pixelArrayOffset ); write32( dibHeaderSize ); write32( xSize ); write32( ySize ); write16( 1 ); write16( bpp ); write32( 0 ); write32( 0 ); write32( 9252 ); write32( 9252 ); write32( 0 ); write32( 0 ); // From M5EPD_Canvas.cpp const uint8_t alphamap[16] = {0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255}; if( bpp == 4 ) { uint8_t buffer[16*4]; int iCount = 0; for( int i = 0 ; i < 16 ; i++ ) { uint8_t value = 255-alphamap[i]; buffer[iCount++] = value; buffer[iCount++] = value; buffer[iCount++] = value; buffer[iCount++] = 0; } writeN(buffer,iCount); } for( int i = 0 ; i < gap1Size ; i++ ) write8( 0 ); uint8_t buffer[960*3]; // log_d("After headers, bytes_written = %d",bytes_written); for( int y = ySize + yPos - 1; y >= yPos ; y-- ) { int iCount = 0; for( int x = xPos ; x < xSize + xPos ; x++ ) { uint16_t pixel = canvas.readPixel(x,y); uint8_t value = min(pixel,(uint16_t)15); switch( bpp ) { case 24: default: value = alphamap[15-min(value,(uint8_t)15)]; buffer[iCount++] = value; buffer[iCount++] = value; buffer[iCount++] = value; break; case 4: if( (x-xPos) % 2 == 0 ) buffer[iCount] = (value << 4) & 0xf0; else { buffer[iCount] |= value & 0x0f; iCount++; } break; } } for( int gap = 0 ; gap < rowGap ; gap++ ) buffer[iCount++] = 0; writeN(buffer,iCount); } bmpFile.close(); if( bytes_written != expectedSize ) log_e("Total bytes written %d vs expected %d",bytes_written,expectedSize); log_d("Screenshot done"); return true; }
-
M5Paper: Support for multiple loaded TTF fonts
Currently the M5EPD library only supports a single loaded TTF font.
For most applications this is fine, but for something like an eReader or web browser it is limiting, as it means you can't have bold/italic/monospaced text.
For my own use, I've modified the library to allow multiple loaded TTF fonts, and I thought I'd share in case it is of use to anyone else.
This is still very experimental, so there may be issues I haven't encountered yet.
The way I've added this support to to use the textfont variable, which isn't currently used when TTF fonts are active. Calling setTextFont switches the currently active TTF font slot, and any subsequent loadFont/createRender/drawString calls will use that slot, until you change it again.
Each loaded font has its own set of render caches, and you can render each font at multiple, different, sizes.
You must call setTextSize each time you call setTextFont, as that is what selects the correct render for the font you have chosen.
This works with either file fonts or header fonts.
Example sketch:#include "M5EPD.h" #define USE_HEADER_FONTS 0 #if USE_HEADER_FONTS #include "OpenSans_Regular.ttf.h" #include "OpenSans_ExtraBold.ttf.h" #include "OpenSans_Italic.ttf.h" #include "OpenSans_ExtraBoldItalic.ttf.h" std::vector<std::pair<const unsigned char*,uint32_t>> fonts = {{OpenSans_Regular_ttf,sizeof(OpenSans_Regular_ttf)} ,{OpenSans_ExtraBold_ttf,sizeof(OpenSans_ExtraBold_ttf)} ,{OpenSans_Italic_ttf,sizeof(OpenSans_Italic_ttf)} ,{OpenSans_ExtraBoldItalic_ttf,sizeof(OpenSans_ExtraBoldItalic_ttf)}}; #else std::vector<String> fonts = {"/Fonts/OpenSans-Regular.ttf","/Fonts/OpenSans-ExtraBold.ttf","/Fonts/OpenSans-Italic.ttf","/Fonts/OpenSans-ExtraBoldItalic.ttf"}; #endif M5EPD_Canvas Canvas(&M5.EPD); void setup() { M5.begin(); M5.EPD.SetRotation(90); M5.EPD.Clear(true); M5.TP.SetRotation(90); M5.RTC.begin(); Canvas.createCanvas(540,960); Canvas.useFreetypeFont(true); Canvas.setFreeFont(nullptr); for( int font = 1 ; font <= 4 ; font++ ) { Canvas.setTextFont(font); #if USE_HEADER_FONTS Canvas.loadFont(fonts[font-1].first,fonts[font-1].second); #else Canvas.loadFont(fonts[font-1],SD); #endif Canvas.createRender(48,32); } Canvas.setTextColor(15); Canvas.setTextDatum(TL_DATUM); int xPos = 64; for( int font = 1 ; font <= 4 ; font++ ) { Canvas.setTextFont(font); Canvas.setTextSize(48); xPos += Canvas.drawString("Test ",xPos,64); } Canvas.pushCanvas(0,0,UPDATE_MODE_GC16); } void loop() {}
In this example I have loaded each font and created its render together, and created all fonts before using any of them. Neither of those is required, you can load fonts and create renders at any time, as long as you select the correct textfont before each operation. You can also delete renders, unload fonts and load a new font into the slot, as long as no canvases are using that slot.
Edit: The updated M5EPD library is available at https://github.com/murraypaul/M5EPD
-
RE: M5Paper: Warning when using multiple canvases
@felmue You can load a single TTF font and pre-render at different sizes in different canvases, that works fine. The problem only occurs with deleteRender, loadFont or unloadFont.
Yes, re-loading the font each time works, provided the performance is acceptable.
Loading the GenSenRounded font takes around 220 ms for me, while Roboto takes only around 50 ms, so depending on the font this isn't something you would want to be doing lots of times per page on an application that needs to be user-responsive. The timings are consistent, so it isn't something that improves with repeated calls due to caching. (Obviously the actual timings will depend on your SD card.)Some other options:
a) Convert the TTF files to headers and include them in your project. This drops the loadFont times to 13/3 ms (and also drops the createRender times, but they are already pretty fast).
Downside is that GenSensRounded uses a huge amount of memory. The sample project with the two fonts included uses over 4MB of the 6.5MB available program memory.b) If you know in advance the font sizes you want to use, convert the TTF fonts to header-stored GFXFF fonts. These are massively smaller, and there is no cross-canvas interference, so you can just load the correct font once for each canvas and not worry about it after that.
Both options are discussed in this thread: https://community.m5stack.com/topic/2732/m5paper-text/19
In general, if you have a simple UI and know in advance which fonts and sizes you want to use, the GFXFF font approach is better, it is fast, uses little memory and doesn't depend on having files stored on the SD card.
-
M5Paper: Warning when using multiple canvases
The M5EPD interface supports creating multiple canvases of different sizes at different positions and updating them independently. For the most part this works fine, but there is a big caveat, you cannot safely use different TTF fonts in different canvases, your app will randomly crash.
The pre-rendered TTF data is static across all In_eSPI instances, but each holds its own pointer to its current render. If that render is deleted by another canvas, either directly by deleteRender, or indirectly by loading a new font, that first canvas now has a pointer to deleted data, and at some point will crash when asked to display text.
To use multiple canvases safely, you can only use a single TTF font across the entire application. Different canvas can use different sizes of that font, that works fine, and other canvases can use GFXFF fonts, they also work fine.
If you change the TTF font in use at runtime, after calling loadFont you have to call createRender for each size in use, and call setTextSize for each canvas using TTF fonts, to update their current render pointer, before any canvas has a chance to try to draw text.
-
RE: M5Paper text
@powersoft This website will convert a TTF font at a specified size to a C header file that you can include and use: https://rop.nl/truetype2gfx/
For example, I downloaded the Ballet font from here: https://fonts.google.com/specimen/Ballet?preview.text_type=custom, and extracted the TTF file.
Then on the website I clicked Choose File, selected that file and clicked Uploaded, then Get GFX Font File.
This created a file called Ballet_Regular_VariableFont_opsz20pt7b.hThe, in Arduino, create a new sketch and copy that header file into the sketch folder, and use this as the code:
#include <M5EPD.h> #include "Ballet_Regular_VariableFont_opsz20pt7b.h" M5EPD_Canvas canvas(&M5.EPD); void setup() { M5.begin(); M5.EPD.SetRotation(90); M5.EPD.Clear(true); M5.RTC.begin(); canvas.createCanvas(540, 960); canvas.setFreeFont(&Ballet_Regular_VariableFont_opsz20pt7b); canvas.drawString("Hello World", 45, 150); canvas.setTextSize(1); canvas.drawString("Hello World", 45, 250); canvas.setTextSize(2); canvas.drawString("Hello World", 45, 350); canvas.setTextSize(3); canvas.drawString("Hello World", 45, 450); canvas.pushCanvas(0,0,UPDATE_MODE_DU4); } void loop() {}
The advantages of this method are:
- No reliance on external files
- Can use any TTF font
- Quicker to switch between different fonts, as no need to render them as bitmaps, that has already been done
- Can use this to display bold/italic, which cannot be efficiently done with TTF fonts
The downsides are:
- The font is pre-rendered at a specific size. The only scaling you can do is to print it x2, x3,... the size, which just upscales the bitmap and looks blocky, as you can see in the example
- So if you need multiple sizes, you need to prerender multiple files and include them all
- You have to make font and size choices at compile time, users cannot switch in and out any font they want
The code does also support loading a TTF font from memory. So you could convert the entire TTF font to a header file and read it directly with M5EPD_Canvas::loadFont(const uint8_t *memory_ptr, uint32_t length). This is an example of a tool that would do this: https://sourceforge.net/projects/bin2header/
I tried this with the Ballet font example, and it crashed the device.
With the standard Arial font, it worked fine, but the font used about 20% of the available program memory, so I don't know if it is really reasonable.To test, just drag the Arial font from your c:\Windows\Fonts directory to somewhere else, run bin2header on arial.ttf to get arial.ttf.h and do this in Arduino:
#include "arial.ttf.h" ... canvas.loadFont(arial_ttf,sizeof(arial_ttf)); canvas.createRender(30,32); canvas.setTextSize(30); canvas.drawString("Hello World", 45, 150);
-
RE: M5Paper text
@powersoft The code showing on the black background? That is a markdown code block.
Before and after the code you want to list, have a line with just three back-quote characters: ```
So:```
this = code;
```
Will display as:this = code;
You can also add a little bit of inline code with single back-quote characters, so `this = code` shows as
this = code
as part of a sentance.If you click the little question mark by the word compose in the top-right of the edit box when writing a post, that will give you a link to the markdown documentation.
-
RE: Make a copy of the canvas
You could loop over x and y, calling readPixel to get individual values, and save them.
Or you could dump the raw buffer, which is available using frameBuffer, and is of size getBufferSize. -
RE: The hight of character
This is available in the TFT_eSPI base class to canvas, but is not exposed to us.
The following seems to work:int height = ((TFT_eSPI&)Canvas).fontHeight();