Posted on

It’s nearly two weeks since I wrote up that butchered USB TTL serial adaptor and no updates! I’ve not been inactive: actually I’ve been having a great time bringing up Forth on those STM32 Cortex M3 boards and writing SPI and I2C access routines.

It may not sound like exciting stuff, but have a look at this bit-banged I2C implementation by JeeLabs - 31 lines including comments — it’s so small.

A colleague has ordered a board of their own, just because it will give them a REPL that they can use to exercise I2C and SPI devices with.

I’ve been writing some Forth words to talk to the Nokia 5110 LCD (also known as the PCB8544). This speaks SPI but with some extra control lines, and it’s one directional - there’s no facility to read from the LCD or even to receive ACKs.

If you’re not familiar with Forth, it’s a stack based language invented by Chuck Moore. “Functions” in other languages are just “words” in forth. Their calling convention is typically just how many words they read of the stack and what they put back. For example, this word takes nothing off the stack, and leaves nothing afterwards:

: lcd-pins ( -- )
    OMODE-PP
    dup LCD_CD io-mode!
    dup LCD_RESET io-mode!
    drop ;

dup duplicates the top word. drop drops the top word. Already I can see a quick win - that second dup is extraneous, if I lose it, I can lose the drop, too. I really want:

: lcd-pins ( -- )
    OMODE-PP
    dup LCD_CD io-mode!
    LCD_RESET io-mode!  ;

This is what Forth programming is like for me, little eureka moments where I realise I can save a byte or a word. You chain these little words together into larger ones. Writing a word that’s more than a few lines long is tricky, and it’s not fun to debug, so you end up keeping your code short and writing lots of very small words.

: lcd-command ( command -- )
    LCD_CD ioc! +spi >spi -spi ;
: lcd-invert ( -- )
    DISPLAYCONTROL DISPLAYINVERTED or lcd-command  ;
: lcd-normal ( -- )
    DISPLAYCONTROL DISPLAYNORMAL or lcd-command  ;

(That ( command -- ) means that it takes one entry off the stack, its command, and consumes it, putting nothing on the stack after it’s done).

The flip side of this very terse and dense code is that it’s reasonably painstaking to write. Bas and I might spend half a lunch break and write 6 lines of code. But they’re a beautiful six lines!

We’ve had some success keeping a framebuffer in RAM and pushing it out to SPI. There’s some glitches to sort though, but I soon hope to have my first Forth pull request. That’ll be a well earned green square.

Noise