I hope it’s all accurate, you might want to check up on me to be sure. I made some assumptions. fillCircleHelper looks like it does semicircles, at least.
The most helpful would be to get @chris to bang out a commented version and do a PR to the example, but your descriptions are accurate. I believe
fillCircleHelper() will do rounded cornered squares though.
I would like share what I have find so far about Arduboy:
It is Arduino Leonardo connected to six buttons, one speaker and 128x64 OLED display.
Display is driven by controller chip that has its own RAM to accomodate 128 x 64 pixels.
In addition, controller has functions to set contrast, inverse mode, display on/off (saves battery) and basic support for hardware scroll.
The display internal memory has a bit weird layout. Display is oraganized in 8 rows, 128 pixels wide and 8 pixels high. These rows are called pages. Each page contains 128 bytes, one per pixel column. Byte has 8 bits maped to 8 rows of page, most significant bit at bottom.
The OLED internal ram is fully adressable but controller’s API strongly suggests sequential fill. For most cases using 1KB array as backbuffer looks to be most practical method. Some games hungry for RAM still could benefit from software emulated text mode.
I believe the used driver is SSD 1306 OLED driver.
There is a piezo and there is a pin. You toogle it, you make noise. The tone() implements handler function for cpu timer interrupt. The function simply toogle speaker bit every time it is called and counts time. By setting timer to a frequency you produce square wave of half frequency.
Noise routine can be written same way. Also some more complicated effects are doable…
Just buttons, no traps here.
It is Atmel’s ATmega32u4
- 8-bit cpu
- 32KB FLASH (28KB available)
- 2560 B SRAM (all available, effectively 1KB consumed by display buffer.
- 1KB EEPROM (all available)
- 1 x 8-bit timer, 2 x 16-bit timer, 2 x10-bit timer (at least one 16-bit and 10-bit available)
I have read the C compiles to effective code, thanks to friendly architecture.
Still, one should realize that it is 8-bit cpu, so operations on bytes are often compiled to single instruction while operations on wider operands (int,long,float) are always compiled to sequence of instructions.
Cpu has 16-bit index registers so I guess array access could be very fast.
Soon or later you probably would like to understand timers and interrupts.
Should be your first stop, it explains a lot.
catmeows, in the ATmega vs. Intel thread you mentioned writing directly to the OLED, but I thought this question would be more relevant here. I assumed we wouldn’t want to write directly to OLED, as that would immediately display anything we send to it, correct? And many games will be building the screen piece by piece, sprite by sprite, drawing a background first and then sprites on top of it, etc. Drawing directly to OLED would probably reveal all of this and look flickery/strange, right? Or does the screen have a built in refresh/“vblank” we can time our writes with, allowing us to skip making our own display buffer?
Also, you seem to say that sound is a simple one tone beeper, but the kickstarter says it’s 2 channel. I’m used to “channel” being used to refer to simultaneous voices, for example the NES has 2 square wave channels, a triangle wave channel, a noise channel and DPCM channel. So how many simultaneous voices do we have on this Piezo speaker?
Yes, you are correct that writing directly to OLED would reveal order of drawing. So for action games the buffer is most suitable method. But imagine you are writing a strategy or adventure game, where smooth display update is not big deal and you are desperate for SRAM space. Then, it is possible to adress a particular place in OLED ram and copy 8 bytes representing character on that place. In that way you can go with 128 bytes long character buffer (or no buffer at all) instead spending 1KB on bitmap buffer. That way, graphics capabilities are restricted to draw characters from font you defined. But nothing prevents you to define semi-graphic characters and use them. Chess game or Sokoban could work this way quite efficiently.
I don’t know details here. The Ardubreakout example uses tone() for sound and it works as described above. I assume Arduboy has connected two pins to speaker but way how to generate sound remains same, you just use two different pins and drive them by two different timers. Actually, there is quite lot of ways how to write tone / sound function, for example driving the two pins from single interrupt.
Read a thread here somewhere where @unclesporky mentioned the bootloader would probably take 2KB, it was also suggested that one could maybe even use a 512B one but that ought to be improbable. What’s with the sudden 4KB drop of usable flash instead of like 2 (excuse me if i’ve missed something important)
Well right in the top of that Ardubreakout code (.ino i think it was) theres a comment containing probably the authors name and a year 2011, well ain’t that long time before even ideas of Arduboy started floating around. I guess it’s probably a code for a leonardo using an inferior sound chip, after all kickstarter and other sources claim the Arrduboy’s speaker to be in fact a 2 channel Piezo, also i think @bateske talked something about usage of an arduino-playtune library if that says smth. about the nature of the chip of sound (sorry for summoning you again Bates : -D and again, OP-s, excuse my ignorance if i’ve left something important unnoticed, just raging and ranting around).
Hi, thanks for reply.
The figure is taken from Arduino IDE with setup for Arduino Leonardo and default bootloader. I think it is good conservative estimation. I would like to hear opinion of somebody who owns arduboy already.
I just uploaded a modified version of the Ardubreakout code (turned off sounds), and this is what it said when uploading:
Sketch uses 16,028 bytes (55%) of program storage space. Maximum is 28,672 bytes. Global variables use 1,643 bytes (64%) of dynamic memory, leaving 817 bytes for local variables. Maximum is 2,650 bytes.
So I guess the max storage is ~28KB, ya?
Hey guys thanks for filling in the blanks as I’ve been super slammed trying to run the kickstarter campaign. Me and @ekem are working on building this and all our internal documentation into a wiki by next week so stay tuned!
I can’t even describe to you how awesome it is to see you all picking up a device I’ve been spending a year of my life bringing to market! Thanks and keep being awesome!!!
X and Y positions start at 0, so the bottom right corner of the screen is at is X = 127 and Y = 63
we need a page like this http://gamebuino.com/wiki/index.php?title=Reference
I played around with the display.drawCircleHelper() function and thought I should document what it does. The
uint8_t cornername argument is a number 1-15, here’s what they do:
I used the emulator that mrboggleman created for the screenshots. The small 1px gaps shown in the screenshots were also displayed on the actual physical device (Developer Kit). Not sure if that’s intentional or not.
display.drawCircleHelper(64, 32, 15, 1, 1);
display.drawCircleHelper(64, 32, 15, 2, 1);
display.drawCircleHelper(64, 32, 15, 3, 1);
display.drawCircleHelper(64, 32, 15, 4, 1);
display.drawCircleHelper(64, 32, 15, 5, 1);
display.drawCircleHelper(64, 32, 15, 6, 1);
display.drawCircleHelper(64, 32, 15, 7, 1);
display.drawCircleHelper(64, 32, 15, 8, 1);
display.drawCircleHelper(64, 32, 15, 9, 1);
display.drawCircleHelper(64, 32, 15, 10, 1);
display.drawCircleHelper(64, 32, 15, 11, 1);
display.drawCircleHelper(64, 32, 15, 12, 1);
display.drawCircleHelper(64, 32, 15, 13, 1);
display.drawCircleHelper(64, 32, 15, 14, 1);
display.drawCircleHelper(64, 32, 15, 15, 1);
Yes, those pixels are a side effect of the way the function calculates the quadrant of the circle.
If you look at the fillCircle function, you’ll see that the first thing it does is draw a quick vertical line down the middle, before drawing two filled halves around it. That’s because those center pixels would be left out.
This is a very nice post, i use it at reference all the time, saves me a lot of time browsing trought the actual .cpp file.
@ekem I feel this needs to be pinned at the top
Ha I have been half tempted to turn it into a wiki topic
Working on getting this turned into a wiki topic
Nope, no vertical sync pin unfortunately. You could write directly to the OLED, but you’d want an algorithm that managed to do so sequentially… such as rendering 8x8 tiles left to right, top to bottom… the exact same way the buffer itself would be drawn… so you could do it without a buffer (and it wouldn’t be weird)… you could have a “text mode” that had no buffer at all - if you didn’t need to know what characters were already there.
The most complex thing is that the graphics hardware is only addressable in 8 pixel vertical chunks… you have to write a full byte at a time to the OLED… so if you want pixel-level precision you need a buffer to remember what individual pixels are already lit/unlit. If you were happy with say a resolution of 128x8 then you could just code directly against the hardware and not worry about the existing contents (since you were writing all 1s or 0s to all 8 pixels in a given “row”). In that case you wouldn’t need to know the existing content of the screen - until you wanted to do transparency or something, etc.