Senoko Battery Board as a Device

The Senoko battery board contains an STM32 chip, and runs its own separate operating system. The computer itself has 10 kilobytes of RAM and 64 kilobytes of storage space, where the operating system lives. This operating system is responsible for keeping the battery charged, monitoring the power button, acting as a secondary clock, and acting as a GPIO port expander.

Many devices talk to one another using the Inter-Integrated Circuit bus, commonly called I2C. In I2C there is one or more "masters" that control the bus, and one or more "slave" devices that are talked to. Masters initiate communication, slaves respond. Examples of I2C devices that are likely in your computer include temperature sensors, small flash memories, and the accelerometer in your phone.

The STM32 in Senoko has the ability to act as both a master and a slave. When talking to the battery charger or gas gauge, it will act as an I2C master. When idle, it will act as an I2C slave and await communication from the main CPU. This allows Novena to talk to Senoko like an ordinary chip, and lets Senoko to appear as a normal device.

Except until today, I was unable to reliably articulate to Senoko what it was I wanted it to do. The way I2C works is it essentially says "Hey, Senoko, give me data". And Senoko will start giving data over I2C from where it left off. You can also say "Hey, Senoko, go to address 4". Senoko will then go to address 4, and next time you ask for data it will start at address 4.

Additionally, I2C supports putting the tow together and saying "Hey, Senoko, go to address 4 and give me data". Unfortunately, due to a bug in the driver, Senoko would ignore the "give to address 4" part and just continue returning data from where it left off. This made drivers very very confused.

Fortunately, after adding I2C logging support to SenokoOS, I spotted the problem. Like all good discoveries the problem was found when I had a bug in the logging function and noticed correct data being where it shouldn't be. I noticed that it wasn't triggering the "receive" methods, even though I knew I was sending data from the master.

It turns out that at the start of an I2C transaction a STARTF eventis generated, and at the end of an I2C transaction a STOPF event occurs. Except if you do everything else at once, as is the case when you say "seek to address 4 and give me data", you'll get two STARTF events and only one STOPF event.

Armed with this knowledge, I was able to patch the I2C slave driver, and lo and behold it started working!

This sequence of events isn't documented in the STM32 reference manual at all. It's very common, but doesn't seem widely supported. And so, with patch 418058, I2C support is now stable, and work on a kernel driver can begin in earnest.