Home |  H2214 GPIO |  I2C LPC2K |  I2C AT91SAM7 |  SPI Thermo |  SPI LCD


A Scheme Interpreter for ARM Microcontrollers: Program Updates (Version 00.0065)

SourceForge.net Logo
 

LPC-H2214 GPIO:


This is a program correction for the LED toggling program as run on an Olimex LPC-H2214 board. Because of the internal representation of integers used in Armpit Scheme, it is not possible to toggle a single memory bit in position 30 which is where the LED is located on the LPC-H2214. However, toggling the bit at position 29 effectively toggles 3 bits at once (those at positions 29, 30 and 31). This feature of Armpit Scheme is exploited in the following corrected version of the GPIO toggler as it aplies to the LPC-H2214 red LED. The code below also works with the multitasking example of version 00.0036.



; Armpit Scheme GPIO Example
; Corrected for LPC-H2214 LED toggling

; define GPIO ports and offsets
(define gpio0 #xE0028000) ; IO0 port (PIN = #x00, SET = #x04, DIR = #x08, CLR = #x0C)
(define pin-status #x00)  ; IOxPIN register offset
(define pin-set    #x04)  ; IOxSET register offset
(define pin-clear  #x0C)  ; IOxCLR register offset

; function to check the status of a pin on a gpio port
(define (is-set? port pin)
  (not (zero? (logand (read port pin-status) (ash 1 (min pin 29))))))

; function to set a pin on a gpio port
(define (set-pin port pin)
  (write (ash 1 (min pin 29)) port pin-set))

; function to clear a pin on a gpio port
(define (clear-pin port pin)
  (write (ash 1 (min pin 29)) port pin-clear))

; function to toggle a pin on a gpio port
(define (toggle port pin)
  (if (is-set? port pin)
      (clear-pin port pin)
      (set-pin port pin)))

; toggle MCU board's LED(s)
(toggle gpio0 30) ; LPC-H2214 red led


 

I2C Communication on the LPC2000:


This is a modification of examples developed for version 00.0036. In version 00.0065, the (flash) command has been replaced by a standard file interface. Scheme startup programs are now written in a file named "boot" using (open-output-file "boot") and associated functions and statements instead of using (flash). This affects code for the slave MCUs used in I2C communications and is reflected in both the "echo" and "remote evaluation" examples below.

Additionally, in version 00.0065, the I2C subsystem automatically packs and unpacks non-immediate objects for safe transmission. This is reflected in the code for both the master and slave MCUs in the "remote evaluation" example below (compare to the corresponding code for version 00.0036).



; Armpit Scheme I2C Communication Example 1: Code for Echo by the Slave Device (flashed as scheme startup program)
; Updated and tested on Tiny2138

; write the startup code to "boot" file
(let ((port (open-output-file "boot")))
  (if (zero? port) #f
      (begin
	(write '(define i2c    #xE001C000) port)
	(write '(define pinsel #xE002C000) port)
	(write '(write (logior #x50 (logand #xFFFFFF0F (read pinsel 0))) pinsel 0) port)
	(write '(write 47   i2c #x10) port)
	(write '(write 103  i2c #x14) port)
	(write '(write #x28 i2c #x18) port)
	(write '(write #x44 i2c #x00) port)
	(write '(write 40 i2c #x0C) port)
	(write '(let echo () (write (read i2c) i2c) (echo)) port)
	(close-output-port port))))




; Armpit Scheme I2C Communication Example 1: Code for the Master Device
; Tested on Tiny2106, unmodified from version 00.0036

; define useful ports
(define i2c    #xE001C000) ; I2C0    port (CONSET = #x00, STAT = #x04, SCLH = #x10, SCLL = #x14, CONCLR = #x18)
(define pinsel #xE002C000) ; PINSEL0 port (0 = #x00, 1 = #x04, 2 = #x14)

; configure MCU pins for I2C0 operation
(write (logior #x50 (logand #xFFFFFF0F (read pinsel 0))) pinsel 0) ; configure P0.2 and P0.3 as I2C via PINSEL0

; initialize the I2C0 peripheral
(begin
  (write 47   i2c #x10) ; set I2C high clock period to 0.783 us (60 MHz pclck, 400kb/s) via I2C0SCLH
  (write 103  i2c #x14) ; set I2C low period to 1.716 us (60 MHz pclck, 400kb/s) via I2C0SCLL
  (write #x28 i2c #x18) ; clear STA and SI via I2C0CONCLR
  (write #x44 i2c #x00)) ; enable I2C on port 0, both master and slave (set I2EN, AA) via I2C0CONSET

; see if anything is available on the input port
(eof-object? (read i2c '#(20)))

; send an integer to the Slave device
(write 123 i2c '#(20))
; read the data back from the Slave device
(read i2c '#(20))

; send #t to the Slave device
(write #t i2c '#(20))
; read the data back from the Slave device
(read i2c '#(20))

; send a string to the Slave device
(write "hello" i2c '#(20))
; read the data back from the Slave device
(read i2c '#(20))




; Armpit Scheme I2C Communication Example 2: Code for Remote Evaluation by the Slave Device
; Updated and tested on Tiny2106

; write the startup code to "boot" file
(let ((port (open-output-file "boot")))
  (if (zero? port) #f
      (begin
	(write '(define i2c    #xE001C000) port)
	(write '(define pinsel #xE002C000) port)
	(write '(write (logior #x50 (logand #xFFFFFF0F (read pinsel 0))) pinsel 0) port)
	(write '(write 47   i2c #x10) port)
	(write '(write 103  i2c #x14) port)
	(write '(write #x28 i2c #x18) port)
	(write '(write #x44 i2c #x00) port)
	(write '(write 40 i2c #x0C) port)
	(write '(let rep () (write (eval (read i2c)) i2c) (rep)) port)
	(close-output-port port))))




; Armpit Scheme I2C Communication Example 2: Code for the Master Device
; Updated and tested on Tiny2138

; define useful ports
(define i2c    #xE001C000) ; I2C0    port (CONSET = #x00, STAT = #x04, SCLH = #x10, SCLL = #x14, CONCLR = #x18)
(define pinsel #xE002C000) ; PINSEL0 port (0 = #x00, 1 = #x04, 2 = #x14)

; configure MCU pins for I2C0 operation
(write (logior #x50 (logand #xFFFFFF0F (read pinsel 0))) pinsel 0) ; configure P0.2 and P0.3 as I2C via PINSEL0

; initialize the I2C0 peripheral
(begin
  (write 47   i2c #x10) ; set I2C high clock period to 0.783 us (60 MHz pclck, 400kb/s) via I2C0SCLH
  (write 103  i2c #x14) ; set I2C low period to 1.716 us (60 MHz pclck, 400kb/s) via I2C0SCLL
  (write #x28 i2c #x18) ; clear STA and SI via I2C0CONCLR
  (write #x44 i2c #x00)) ; enable I2C on port 0, both master and slave (set I2EN, AA) via I2C0CONSET

; remotely sum a list of numbers
(write '(+ 3 5 7 9 11 13 15) i2c '#(20))

; get the result back from the Slave device
(read i2c '#(20))

; closure to get mcu-id
(define (mcu-id) (ash (read i2c #x0C) -1))

; read remote mcu-id
(write (list mcu-id) i2c '#(20))

; get the result back from the Slave device
(read i2c '#(20))


 

I2C Communication on the AT91SAM7:


This is a new example that illustrates I2C communication on an AT91SAM7S256 MCU. The code if very similar to that of Example 1, above, for the LPC2000 family. However, the AT91SAM7S family of MCUs supports master mode I2C communicatin only and does not implement clock-stretching (the AT91SAM7SE series apparently remedies this). Consequently, only the master MCU code is given below. Additionally, because of the lack of clock stretching, the communication rate is reduced to 50 kbit/s to give sufficient time for the slave MCU to perform garbage collection (if needed when receiving large non-immediate objects) while remaining synchronized with the master.



; Armpit Scheme I2C Communication Example: Master mode only (Tiny2138 slave echoes data as in Example 1, above)
; Tested on SAM7-H256

; define useful ports
(define i2c  #xFFFB8000) ; TWI (CR = #x00, MMR = #x04, IADR = #x0C, CWGR = #x10, IER = #x24)
(define pmc  #xFFFFFC00) ; PMC (PCER = #x10)
(define pioa #xFFFFF400) ; PIOA (PER = #x00, PDR = #x04, ASR = #x70, BSR = #X74)

; Configure TWI (I2C) pin function and com speed to 50kb/s
(begin
  (write #x18    pioa #x04)   ; Disable the GPIO function for TWI pins (pins/bits 3, 4) via PIOA_PDR
  (write #x18    pioa #x70)   ; Select TWI function (Periph A, pins/bits 3, 4) via PIOA_ASR
  (write #x0200  pmc  #x10)   ; Enable clock/power for TWI (bit 9) via PMC_PCER
  (write #x3234F i2c  #x10)   ; Set clock wave generator for 50 kb/s at 48MHz via TWI_CWGR
  (write #x0107	 i2c  #x24))  ; Enable interrupts (nack, txrdy, rxrdy, txcomp) via TWI_IER


; send a list
(write '(list 1 2 3 #(1 4 5) #\b "woades") i2c '#(20))
; get the list back
(read i2c '#(20))

; send a long string
(write (make-string 1000 #\p) i2c '#(20))
; get the string back
(define qq (read i2c '#(20)))
; verify the string's integrity
(string-length qq)   ; -> 1000
(string-ref qq 600)  ;  -> #\p



 

SPI Reading of a MAX6675 Thermocouple Conditioner:


This is a new example of how to use Armpit Scheme and the MCU's SPI interface to read temperature values from a type-K thermocouple using the MAX6675 Cold-Junction-Compensated K-Thermocouple-to-Digital Converter chip by Maxim Inc.



; Armpit Scheme SPI Communication Example: Reading a MAX6675 Thermocouple Conditioner
; Tested on LPC-H2148

; define useful ports
(define gpi0 #xE0028000) ; GPIO0 port (PIN = #x00, SET = #x04, DIR = #x08, CLR = #x0C)
(define spi0 #xE0020000) ; SPI0 port (CR = #x00, SR = #x04, DR = #x08, CCR = #x0C)
(define mxcs (ash 1 20)) ; chip select line P0.20 (inverted)

; configure SPI and I/O lines
; 1- set P0.20 as output (select/deselect chip)
; 2- set P0.20 high (deselect chip)
; 3- configure SSP P0.4=SCK, P0.5=MISO, P0.6=MOSI via pinsel-0 bits 9:8, 11:10, 13:12
; 4- set spi comm parms -- SSPCR (#x00) 15:8-bits=9, 5-MSTR=1, 4-CPHA=1, 3-CPOL=1
; 5- set spi comm speed -- SSPCCR (#x0C) prescale
; 6- set SSEL0 (a GPIO) high to avoid SPI auto-switchback to Slave Mode on noise
(begin
  (write (logior mxcs (read gpi0 #x08)) gpi0 #x08)
  (write mxcs gpi0 #x04)
  (let ((pnsl #xE002C000))
    (write (logior #x1500 (logand #xFFFF00FF (read pnsl #x00))) pnsl #x00))
  (write #x002C spi0 #x00)
  (write 240    spi0 #x0C)
  (write (logior (ash 1 7) (read gpi0 #x08)) gpi0 #x08)
  (write (ash 1 7) gpi0 #x04))

; function to read from chip (write 0 to it to get data)
; 1- select chip   -- clear P0.20 (gpi0 #x0C)
; 2- write 0 to it -- SSPDR (spi0 #x08)
; 3- wait for data -- SSPSR (spi0 #x04)-- #x80 is x-fer complete bit
; 4- deselect chip -- set P0.20 (gpi0 #x04)
; 5- extract data  -- SSPDR (spi0 #x08)
(define (rdtm)
  (write mxcs gpi0 #x0C)
  (write 0 spi0 #x08)
  (let wait ((stat 0))
    (if (= 0 (logand #x80 stat))
	(wait (read spi0 #x04))
	(begin
 	  (write mxcs gpi0 #x04)
	  (/ (ash (read spi0 #x08) -3) 4)))))

; read the temperature
(rdtm)



 

SPI Writing to a NOKIA-like Color LCD:


This is a new example of how to use Armpit Scheme and the MCU's SPI interface to write to a 128x128 bit color LCD available from Sparkfun Electronics.



; Armpit Scheme SPI Communication Example: Writing to a Color LCD
; tested on LPC-H2148

; define useful ports
(define gpi0 #xE0028000) ; GPIO0 port (PIN = #x00, SET = #x04, DIR = #x08, CLR = #x0C)
(define spi0 #xE0020000) ; SPI0 port (CR = #x00, SR = #x04, DR = #x08, CCR = #x0C)
(define lcds (ash 1 20)) ; chip select line P0.20 (inverted)
(define lcdr (ash 1 21)) ; chip reset  line P0.21 (inverted)

; configure I/O lines:
; 1- set P0.20 and P0.21 to outputs
; 2- set P0.20 high (deselect lcd)
; 3- configure SSP P0.4 as SCK, P0.6 as MOSI via pinsel0 bits 9:8 and 13:12
; 4- set SPI comm parms -- SSPCR  (#x00) 15:8-bits=9, 5-MSTR=1, 4-CPHA=1, 3-CPOL=1
; 5- set SPI comm speed -- SSPCCR (#x0C) prescale
; 6- set SSEL0 (a GPIO) high to avoid SPI auto-switchback to Slave Mode on noise
(begin
  (write (logior lcdr (logior lcds (read gpi0 #x08))) gpi0 #x08)
  (write lcds gpi0 #x04)
  (let ((pnsl #xE002C000))
    (write (logior #x1100 (logand #xFFFF0CFF (read pnsl #x00))) pnsl #x00))
  (write #x093C spi0 #x00)
  (write 60     spi0 #x0C)
  (write (ash 1 7) gpi0 #x04))

; function to wait for SPI status to be ready
(define (spwt stat)
  (if (= 0 (logand #x80 stat))
      (spwt (read spi0 #x04))
      #t))

; function to write a list of commands and data to lcd
(define (wlcd clst)
  (write lcds gpi0 #x0C)
  (let lwrt ((lst clst))
    (if (eq? lst '())
        (write lcds gpi0 #x04)
	(begin
	  (write (logxor #x0100 (car lst)) spi0 #x08)
	  (spwt (read spi0 #x04))
	  (lwrt (cdr lst))))))

; reset the lcd -- clear P0.21
(write lcdr gpi0 #x0C)

; bring up the lcd: 
; 1- de-assert reset -- set P0.21
; 2- send commands -- DISCTL COMSCN OSCON SLPOUT VOLCTR TMPGRD DATCTL
; 3- send commands -- RGBSET8 NOP DISINV
; 4- send commands -- PWRCTR NOP DISON
; 5- send command  -- VOLUP, repeatedly (adjust contrast)
(begin
  (write lcdr gpi0 #x04)
  (wlcd '(#x01CA 0 31 11 #x01BB 1 #x01D1 #x0194 #x0181 5 3 #x0182 1 #x01BC 0 0 1))
  (wlcd '(#x01CE 0 2 4 6 8 10 12 15 0 2 4 6 8 10 12 15 0 4 9 15 #x0125 #x01A7))
  (wlcd '(#x0120 15 #x0125 #x01AF))
  (let vup ((n 160))
    (if (< n 0) #t
	(begin
	  (wlcd '(#x01D6))
	  (vup (- n 1))))))

; function to return a list of lcd commands that put a pixel of color c at position x,y on the lcd
; (raw lcd commands are: PASET y end CASET x end RAMWR c)
(define (pix x y c)
  (list #x175 (+ y 2) 131 #x115 x 131 #x15C c))

; draw a blue cosine wave
(let pcos ((x 0) (plst '()))
  (if (> x 130)
      #t
      (begin
	(wlcd (pix x (- 64 (round (* 30 (cos (/ x 10))))) 10))
	(pcos (+ x 1)))))



Last updated June 7, 2007

bioe-hubert-at-sourceforge.net