Close

Easy I2C with STM8 eForth

A project log for eForth for cheap STM8S gadgets

Turn cheap modules from AliExpress into interactive development kits!

thomasThomas 12/03/2020 at 21:420 Comments

I had some fun experimenting with the STM8 I2C peripheral. Working around its quirks and designing a code efficient yet reliable and easy to use I2C driver was a challenge. In my previous log entry I mentioned improvements for mixing control structures with optimized assembler code in ISRs.

After testing some alternatives I ended up with a very simple approach:

The ISR is now really easy to use. Here is the code for a 24C64 EEPROM:

\res MCU: STM8S103

\ Initialization code, e.g. for 100kBit
#require I2I

\ ISR based I2C "Master transmitter/receiver"
#require I2CMA

\ temporary constants for the I2C user code
I2ISR 2 + CONSTANT TCOUNT  \ char number of bytes TX
I2ISR 3 + CONSTANT RCOUNT  \ char number of bytes RX
I2ISR 4 + CONSTANT TPOINT  \ points to TX buffer, starting with CMD/ADDR
I2ISR 6 + CONSTANT RPOINT  \ points to RX buffr

80 CONSTANT SA24C64

NVM

VARIABLE EADDR
VARIABLE BUFFER 6 ALLOT

: write ( a c -- )
  \  BUFFER follows EADDR, c=0 at least writes the address
  ( c ) 2+ TCOUNT C!   \ TCOUNT, # bytes incl. EADDR
  ( a ) EADDR !        \ set EEPROM address
  EADDR TPOINT !       \ initialize transfer pointer
  SA24C64 I2S
;

: read ( a c -- )
  BUFFER RPOINT !      \ set read pointer to buffer
  ( c ) RCOUNT C!      \ RCOUNT
  ( a ) 0 write        \ zero-write sets EADDR and starts the read sequence
;

RAM

\\ Example

I2I
$AA55 BUFFER !
$0011 2 write
$0011 2 read

The ISR deals with the different even sequences in the reference manual and it also catches errors.

Using the error event writing a simple I2C scanner is very easy:

\res MCU: STM8S103

\ Initialization code, e.g. for 100kBit
#require I2I

\ ISR based I2C "Master transmitter/receiver"
#require I2ISR

: scan ( -- )
  I2I
  127 FOR 
    I 16 MOD 15 = IF CR THEN 
    I2S I2W  \ send address and wait for ACK/NACK
    I2ISR @ 0< IF ."  --" ELSE I . THEN  
  NEXT
;

scan
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 80
 79 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ok

A negative value in I2ISR indicates that there was a transmission error (the MSB also contains the error event flags). In the listing above shows replies from a DS1621 at A2:0=7 (79) and from a 24C64 EEPROM at A2:0=0 (80).

I also wrote test code for the DS1621 temperature sensor (which has a 8 bit command instead of the 16 bit address in the case of the EEPROM) which was just a few lines of code. Accessing any 7bit I2C device should be really easy now.

Edit: @Eelco did some serious testing with the well known SSD1306 128x64 OLED display.  After discussing a slightly more involved API (extra command interface) it was decided to keep the original simple API. Working code for the SSD1306 is in this GitHub Gist comment.

Discussions