Vista de Lectura

Hay nuevos artículos disponibles. Pincha para refrescar la página.

2024 Tiny Games Contest: A Flappy Seagull Game With Sound in Only 500 Bytes

It was probably a reasonable assumption that the “Tiny” in our recently concluded Tiny Games Contest mostly referred to the physical footprint of the game. And indeed, that’s the way most of the entries broke, which resulted in some pretty amazing efforts. [Anders Nielsen], however, took the challenge another way and managed to stuff a seagull-centric side-scroller into just 500 bytes of code.

That’s not to say that the size of [Anders]’s game is physically huge either. Flappy Larus, as he calls his game, runs on his popular 65uino platform, a 6502 microcontroller in the familiar Arduino Uno form factor. So it’s pretty small to begin with, and doesn’t even need any additional components other than the tiny OLED screen which has become more or less standard for the 65uino at this point. The only real add-on is a piezo speaker module, which when hooked up to the I2C data line happens to make reasonable approximations of a squawking seagull, all without adding a single byte of code. Check out a little game play in the video below.

Flappy Larus may be pretty simplistic, but as we recall, the game it’s based on was similarly minimalist and still managed to get people hooked. The 2024 Tiny Games contest is closed now, but if you’ve got an idea for a tiny game, we’d still love to feature it. Hit the tip line and we’ll take a look!

2024 Tiny Games Challenge

I2C For Hackers: Digging Deeper

Last time, I gave you an overview of what you get from I2C, basics like addressing, interface speeds, and a breakdown of pullups. Today, let’s continue looking into I2C capabilities and requirements – level shifting, transfer types, and quirks like combined transfers or clock stretching.

Level Shifting

Today, the overwhelming majority of I2C devices are 3.3 V logic. but this wasn’t always the case. If you work with old tech or with I2C on VGA/DVI/HDMI ports, you will see 5 V I2C networks, and if you work with very new tech, you will see 1.8 V I2C networks; rarely, you might even see 2.5 V networks!

Interfacing 5 V devices with a 3. 3V controller, it might not be necessary to level shift. You need to a) wire pullups to 3.3 V, and b) win the device input tolerance lottery. Same goes interfacing 3.3 V devices with 1.8 V hosts – wire up pullups to 1.8 V and pray to the stars. It can work in production – here’s Adafruit taking the 3.3 V-pulled-up Raspberry Pi I2C bus, and connecting it to a 5 V-powered MCP23017 chip that drives a 5 V-connected HD44780 display.

If your arrangement is different, or you’re experiencing a problem, you will want a level shifter circuit. At their simplest, two N-FETs like 2N7002 will do wonders. If you want smaller PCB footprint, better parameters, or more channels, there are level shifter chips, with many of them wonderfully suited for I2C (read the datasheet!). As we’ve featured before, some shifter ICs are too smart for their own good, while others will do just fine – if in doubt, remember to use your logic analyzer judiciously.

Two Ways To Talk

There are two kinds of I2C transfers you could expect to perform – I’d call them “simple transfers” and “register transfers”. With simple transfers, you send an address, and after the device ACKs, you either send or receive a single byte – it’s just like working with a shift register. With register transfers, you send an address, then a register number, and the device sends you the “contents” of that register – it’s more like working with an SPI display.

The PCF8574 is an I2C GPIO expander that does simple transfers. It has eight GPIO pins, and it only does simple transfers. How does that work, given it does both input and output? Well, the PCF8574 has only three possible states for all pin, with two of them combined together. The “Low” state (writing 0) is a hard pull down to GND. The “High” state (writing 1) is a weak pull to VCC – which also makes the pin work as an input with a pullup enabled. To check the input state, just read the expander state, and see if any of the pins you’ve set to 1 are now reading as 0. You can’t do a lot of high-side driving, sure, but you can still drive LEDs and check buttons, plus, this scheme is dead simple and covers a ton of use cases.

A good few I2C devices use simple transfers – the LM75 temperature sensor, for instance, only has to return temperature. You can read out multiple bytes at once, of course – simple transfers aren’t inherently limited to a single byte! PCF8575, the 16-bit sister of the PCF8574, has 16 GPIOs, I’ve used simple transfers with an ATMega328P keypard controller I created at some point – it would return keycodes, taken from a ring buffer. However, at some point, I decided to add more features to it, like ADC reading to help out a Pi Zero it was connected to, and had to upgrade it to register transfers.

The MCP23017 is a GPIO expander that uses register transfers. It has 16 GPIO pins, and a ton of features, each with their own register. Since one register contains 8 bits and we have 16 GPIOs, there are two registers per feature, and as such, there are two registers for pin directions, two for enabling integrated pullups, two for reading out input states, two for setting pins as outputs, and so on. They can even be arranged in two different ways, one backwards compatible with a different chip, by changing a bit in the status register! It’s a fair bit more complex chip than the PCF8574, but the complexity pays off where you need it.

I2C EEPROMs work with register transfers, too – some use 8-bit addresses, which allows for up to 256 bytes of storage. Higher-capacity EEPROMs use 16-bit (two-byte) addresses, where you’re expected to send in two bytes before you can read data out; if you try to read from such an EEPROM using two-byte addresses, you will just read back zeroes, so beware!

Quirks

But what if the device can’t keep up with the multi-byte transactions that your microcontroller is asking for? Maybe you have an EEPROM that needs time before it can read out a value from its internal memory so that it your MCU can receive it, maybe it’s a sensor that needs to average some values quickly and it just can’t catch up with even the lax timing requirements of 100 kHz I2C.

There’s a solution – it’s called clock stretching, and it’s basically an I2C device holding SCL low after receiving a byte, extending ACK state for a long time, until it can actually return meaningful data. As long as SCL is low, the controller should wait for the device. It’s essentially a way for a device to say “wait, not yet, I need some time before I can give you what you’re looking for”.

Raspberry Pi didn’t support clock stretching for the longest time due to a silicon bug. Every single Pi version before Pi 4 couldn’t handle clock stretching, including all of the Pi Zero versions released at the time of writing this article. The workaround, if you need one – use software I2C. It consumes more CPU since you have to use a kernel driver that bitbangs the bus, but it does have functional clock stretching. And of course the Raspberry Pi isn’t alone: if you are likely to need clock stretching, make sure that the microcontroller hardware peripheral supports it properly.

Next time, we dive into the physical layer, look at logic analyzer traces, understand how communication happens, and the ways it can break despite our best intentions.

Ryobi Battery Pack Gives Up Its Secrets Before Giving Up the Ghost

Remember when dead batteries were something you’d just toss in the trash? Those days are long gone, thankfully, and rechargeable battery packs have put powerful cordless tools in the palms of our hands. But when those battery packs go bad, replacing them becomes an expensive proposition. And that’s a great excuse to pop a pack open and see what’s happening inside.

The battery pack in question found its way to [Don]’s bench by blinking some error codes and refusing to charge. Popping it open, he found a surprisingly packed PCB on top of the lithium cells, presumably the battery management system judging by the part numbers on some of the chips. There are a lot of test points along with some tempting headers, including one that gave up some serial data when the battery’s test button was pressed. The data isn’t encrypted, but it is somewhat cryptic, and didn’t give [Don] much help. Moving on to the test points, [Don] was able to measure the voltage of each battery in the series string. He also identified test pads that disable individual cells, at least judging by the serial output, which could be diagnostically interesting.  [Don]’s reverse engineering work is now focused on the charge controller chip, which he’s looking at through its I2C port. He seems to have done quite a bit of work capturing output and trying to square it with the chip’s datasheet, but he’s having trouble decoding it.

This would be a great place for the Hackaday community to pitch in so he can perhaps get this battery unbricked. We have to admit feeling a wee bit responsible for this, since [Don] reports that it was our article on reverse engineering a cheap security camera that inspired him to dig into this, so we’d love to get him some help.

❌