Pico + display pack. Speed query

I created a python program to display a wave on the display pack. This works fine but is too slow so I created the same program in C. This is faster, but still too slow, and I am surprised that there is little difference in speed between python and C.

Roughly: python takes 2.3 seconds and C takes 1.3 seconds.
I expect I’m doing something daft, but have no idea what ??

Python code:

import picodisplay as display
import math

width = display.get_width()
height = display.get_height()

display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565)
display.init(display_buffer)

display.set_led(0,0,0) # Turn the LED off

display.set_backlight(1.0)
display.set_pen(51, 153, 255)
display.clear()

display.set_pen(0, 51, 204)
display.rectangle(0,0,240,20) # dark blue sea base
display.update()

for x in range(240):
angle = x*1.5
y = int(math.sin(math.radians(angle)) * 15) + 14

display.set_pen(0, 51, 204)  # dark blue
display.rectangle(x,20,2,y)
                   
display.update()

C code:

#include “pico_display.hpp”
#include <math.h>

using namespace pimoroni;

uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
PicoDisplay pico_display(buffer);

int angle;
int x;
int y;

double degtorad(double degree) { // degrees > radians
double pi = 3.14159265359;
return (degree * (pi / 180));
}

int main() {
pico_display.init();

pico_display.set_led(0, 0, 0);   // led off

pico_display.set_backlight(150);    //0 - 255
pico_display.set_pen(51, 153, 255); //   blue sky
pico_display.clear();

pico_display.set_pen(0, 51, 204);   //dark blue sea base
Rect sea_rect(0,0,240,20);     
pico_display.rectangle(sea_rect);  

pico_display.update();

for(x=0; x<240; x=x+2) {
   angle = x*1.5;
   y = int(sin(degtorad(angle)) * 15) + 14;
 
   Rect db_rect(x,20,2,y);  
   pico_display.set_pen(0, 51, 204);  //dark blue wave
   pico_display.rectangle(db_rect);

   pico_display.update();
}   

}

A couple of suggestions:

EDIT: Derp, posted this prematurely.

The Pico doesn’t have a native floating point unit, though there’s apparently some mathematical hackery going on to accelerate it in the silicon. Still, it’ll not be as fast as microcontrollers with floating point units.

Second, you probably want pico_display.update(); to be outside the for loop: that pushes 115KB of data per transaction, so if you’re running it every loop that’s a lot of data.

Your Python script seems to run through every value of 0-240 whereas the C runs every other value, so that comparison isn’t going to be fair. As far as I know MicroPython modules baked into the firmware are (semi?) compiled, so they’ll probably be faster than standard Python. I think Pimoroni’s modules really just call the underlying C API.

(Just FYI, if you’re posting blocks of code wrap the whole thing in triplets of backticks, it formats the whole thing in an easier to read way).

That pico_display.update() inside the loop will be the killer.

I just had a similar experience on the Pico explorer display and I am doing similar floating point arithmetic. It was too slow so I switched to C++ and it is about 100x faster. In both the Python and C++ code I only do the update once everything has been drawn.

Many thanks - a quick edit confirms that you are absolutely correct !
The code I posted is a tiny fragment: now to think about redesigning the project …

Shoe, Many thanks. I was wondering if something to do with updating the display was the problem, but I’m not (yet) at home with the idea of stuffing all sorts of conflicting data into a buffer and then updating the screen in one go. It all works fine now, although it is still, as you’d expect, the case that the screen updates hugely reduce the speed difference between python and C
And thanks for the back ticks info.
FWIW I’m hugely impressed by the pico and the growing community surrounding it.

Glad you got it working, it’s a nice piece of kit isn’t it? I bough a pico and a bunch of accessories at lauch but I’ve not had as much time to poke at them as I’d like because of work. I’m really curious about the PIO system.

I just plugged your code into my project and changed it for the Pico Explorer display. I changed the x to increment by 1 rather than 2, just the one .update at the end and put the loop inside another loop repeating 1000 times. In C++ it completed in 7 seconds. So it would have been doing 2000x what your code was doing and it took 7 seconds compared to 1.3 seconds. I wonder if the Pico display is slower than the Pico Explorer’s display. Would be good to get the same code running on each to test if that is the case as I was intending to buy a Pico Display Pack but may not if it turns out to be much slower.

I’ll be happy to run a test on the display. Would you like to post your code so that I can, possibly, avoid making daft mistakes !

I have a project that is restricted to integer arithmetic and that fills the screen with points 200x over. This should check the screen performance rather than the Pico’s floating point arithmetic. On my Explorer base it takes between 5 and 6 seconds. I haven’t worked out how to do execution duration in C++ on the Pico yet so you just have to count I’m afraid.

I created a version for the Pico Display. When I run it on my Pico Explorer it does run but I get corruption down each side of the screen - I think that is probably reasonable judging by the differences in the two displays.

I’m set up in Visual Studio Code on a Windows 10 machine. Do you want the whole source code project so you can compile there or just the uf2 or I could just post the code here - it is very simple.

Cheers.

Perhaps it’s best to have the source code in case there is something that needs tweaking for the pico display ? I haven’t managed to get VS code set up properly, but happily compiling from the command line.

Incidentally the pico+display project here is running perfectly with python. It’ good to know that C is available if needed but I probably won’t.

My programming background is a mixture of commercial database apps with RAD front ends and low level control code with bits of machinery - I’m very new to hands-on graphics. So it was a bit of a revelation to realise that one can do as much complicated shuffling of data into the display buffer as you like without appearing to have the slightest effect on the speed of the program. Good fun so far.

Fair winds, Nick

Try this. My Explorer does it in 5102 milliseconds. It should go red and then green and display the number of milliseconds it took:

#include <stdio.h>
#include "pico/stdlib.h"
#include "pico_display.hpp"

using namespace pimoroni;

uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT];
PicoDisplay pico_display(buffer);  

void doTest() { 
  pico_display.set_pen(128, 0, 0);
  pico_display.clear();
  pico_display.update();

  pico_display.set_pen(0, 128, 0);

  for(int z=0; z<=200;z++) {
    for(int y=0; y<=135; y++) {
      for(int x=0; x<=240; x++) {      
        pico_display.pixel(Point(x, y));     
      }      
    }
  }

  pico_display.update();
}   


int main() {
  stdio_init_all();

  pico_display.init();
  pico_display.set_backlight(100);
  pico_display.set_pen(0, 0, 0);
  pico_display.clear();    
  pico_display.update();

  absolute_time_t start_time = get_absolute_time();
  doTest();
  absolute_time_t end_time = get_absolute_time();
  
  pico_display.set_pen(128, 128, 128);
  char temp[32];
  sprintf(temp, "%lld", absolute_time_diff_us(start_time, end_time)/1000);
  pico_display.text(temp, Point(5, 5), 235, 5);
  pico_display.update();
}

Cheers,

Steve

Splendid, I’ll run it first thing in the morning.

Rgds,

Nick

Hi Steve,

Approx 4600 milliseconds.

I compiled the code, copied to pico, nothing interesting happened.

Spent ages looking at it, as usual couldn’t see anything wrong, looked up a couple of things, still couldn’t see anything … eventually realised that it needs “pico_display.set_backlight( );”

Worked ok, but text unreadable - the pico display font is dreadful. decided not to bother with text, added red & green led indications before & after doTest(), increased outer loop to 20,000, ran with stopwatch,
46.11 seconds.

huzzah !

Hi Nick,

Sorry about that. Since the Explorer Base display’s backlight is not adjustable I had removed the set_backlight statement. Then when I created the Display Pack version (which I don’t possess yet) I forgot to put it back in - oops. Glad you got it working - I’ll go back and edit my post just in case other people copy/paste it.

It looks like the Display Pack might be a little faster than the Explorer Base. If you re-code in Python you should see that it will take much, much longer to run. Yes, the font is pretty bad when scaled up.

My current project is a clock / timer / stopwatch with drawn arcs. In Python my algorithm (which may be optimisable) is too slow to update once per second but in C++ it gets the job done in about 300ms.

Cheers,

Steve

Hi Steve,

I coded your test in python: 3 minutes ! Useful to have a comparison of C and Python.

I’m just playing about enjoying learning about tiny graphics. Project is an ‘art object’ birthday present for a grown-up daughter who, like me, is rather fond of ducks.

So we have a big moving wave, with a duck bobbing on the surface, and a sun, and moving clouds and the backlight dims when clouds cover the sun … In Python the wave period is about 1.2 seconds which as fine and quite mesmeric to look at, and so far adding more ( and more … ) graphics bits doesn’t apper to impact speed in any noticeable way. It’s great to know that if it hits the buffers I can easily recode in C.

Rgds, Nick