Home |  Prompt |  Files |  SD-card |  Library Party |  Runge-Kutta |  Runge-Kutta Library |  FFT |  Expert System |  ARMSchembler/Compiler


A Scheme Interpreter for ARM Microcontrollers:
Program Examples for Snapshot 00.0250

SourceForge.net Logo
 

Preamble:


Program examples for this snapshot are similar to those of the previous snapshot, but with modifications outlined in the ChangeLog. The GPIO and Threads examples have been moved to the MCU-specific examples page. An SD-card reading/writing example is presented. The Expert System example now uses the built-in defined? function (re-instated from a prior release). The ARMSchembler and Compiler are presented here rather than in a separate "Library Examples" page.


 

Prompt:


The code below examplifies how to modify the Armpit Scheme prompt. It re-defines the (prompt) function to to get a version number, and uses (gc) to find the number of free bytes, and prints those out on the current-output-port (the number of free bytes is divided by eight using a bitwise-arithmetic-shift so that the number of free cons cells is actually displayed). Once the code has been evaluated, the system prompt becomes that produced by this user-defined (prompt) function rather than the built-in (prompt) primitive.



; Armpit Scheme Prompt Example
; tested on LPC-H2214, LPC-H2888, CS-E9302, TCT-Hammer, TI-Beagle


; example prompt
(begin
  (define prst
    (string-append "aps" (substring version 2 7) ">"))
  (define (prompt) (write (bitwise-arithmetic-shift (gc) -3)) (display prst)))


 

Files:


The code below examplifies writing to and reading from files, listing files, erasing all files and unlocking the file system (if it remained locked due to a multitasking crash). It is the same as in the previous version except that spaces are written to the file in-between top-level items. Also, note that for the OMAP3530 Live-SD version (BeagleBoard and Overo Tide), files are written to and read from SD-card (native file system for those MCUs), and there is no (erase) function (that erases all files).



; Armpit Scheme File Example
; tested on LPC-H2214, LPC-H2888, CS-E9302, STM32-H103, LM3S1968-EVB, TI-Beagle


; unlock file system (optional - file system may get locked during read/write errors)
(unlock)

; erase all files (optional - may take a few seconds -- not available on OMAP3530)
(erase)

; list all files
(files)

; write some data to a file named zag
(let ((port (open-output-file "zag")))
  (if (zero? port) #f
     (begin 
       (write "hello" port)
       (display #\space port)
       (write '(1 2 3) port)
       (display #\space port)
       (write 3.4e-2 port)
       (display #\space port)
       (write (make-vector 140 123456) port)
       (close-output-port port))))
 
; list all files
(files)

; read and display data from a file named zag
(let ((port (open-input-file "zag")))
  (if (zero? port) #f
     (let loop ((val (read port)))
        (if (eof-object? val)
           (close-input-port port)
           (begin
             (if (not (vector? val))
               (write val)
               (begin
                 (write (vector-length val))
                 (write (vector-ref val 0))
                 (write (vector-ref val (- (vector-length val) 1)))))
             (newline)
             (loop (read port)))))))


 

Files on SD-card:


The code below adapts the above example to the case of writing and reading to an SD-card (for boards where the interface is implemented --see ChangeLog-- and differs from that of the native file system). The SD card file system is FAT16, with 8.3 file names, limited to 2 GB (max) cards, and ARMPit Scheme knows only about the top-level directory of this file system. The built-in SD-card port is named SDFT.



; Armpit Scheme SD-card File Example
; tested on LPC-H2214, CS-E9302, STM32-H103, LM3S6965-EVB, SFE-Logomatic2


; initialize communications with the card (repeat until non-#f)
(sd-init)

; list all files on SD card
(files SDFT)

; write some data to a file named zag on the SD card
(let ((port (open-output-file "zag" SDFT)))
  (if (zero? port) #f
     (begin 
       (write "hello" port)
       (display #\space port)
       (write '(1 2 3) port)
       (display #\space port)
       (write 3.4e-2 port)
       (display #\space port)
       (write (make-vector 140 123456) port)
       (close-output-port port))))
 
; list all files on the SD card
(files SDFT)

; read and display data from a file named zag on the SD card
(let ((port (open-input-file "zag" SDFT)))
  (if (zero? port) #f
     (let loop ((val (read port)))
        (if (eof-object? val)
           (close-input-port port)
           (begin
             (if (not (vector? val))
               (write val)
               (begin
                 (write (vector-length val))
                 (write (vector-ref val 0))
                 (write (vector-ref val (- (vector-length val) 1)))))
             (newline)
             (loop (read port)))))))


 

Library Party:


The code below adapts the first library example given in section 7.3 of r6rs to ArmPit Scheme. The modifications are mainly related to the lack of "rename", "only" and "prefix" forms in this snapshot. It is the same as in the previous release except for the use of (libs), now part of the core (but a reverse order listing relative to 00.0241 functions), and for the use of (erase-libs) (also part of the 00.0250 core).



; Armpit Scheme Party Library Example
; Tested on SFE-Logomatic V2.0

; build the stack library
(library
 (stack)
 (export stack:make stack:push! stack:pop! stack:empty!)
 (import (rnrs))
 (define (stack:make) (list '()))
 (define (stack:push! s v) (set-car! s (cons v (car s))))
 (define (stack:pop! s)
   (let ((v (caar s)))
     (set-car! s (cdar s))
     v))
 (define (stack:empty! s) (set-car! s '())))

; build the balloons library
(library
 (balloons)
 (export balloon:make balloon:push balloon:pop)
 (import (rnrs))
 (define (balloon:make w h) (cons w h))
 (define (balloon:push b amt)
   (cons (- (car b) amt) (+ (cdr b) amt)))
 (define (balloon:pop b) (display "Boom! ")
   (display (* (car b) (cdr b)))
   (newline)))

; build the party library
(library
 (party)
 (export make push push! make-party pop!)
 (import (rnrs) (stack) (balloons))
 (define make balloon:make)
 (define push balloon:push)
 (define push! stack:push!)
 (define (make-party)
   (let ((s (stack:make)))
     (push! s (balloon:make 10 10))
     (push! s (balloon:make 12 9))
     s))
 (define (pop! p)
   (balloon:pop (stack:pop! p))))

; list all libraries (00.0241-style)
(map (lambda (e) (list (vector-ref (vector-ref e 0) 0))) (vector-ref (_GLV) 12))

; list all libraries (00.0250-style)
(libs)

; import the party library
(import (party))

; have a party (test program)
(begin
  (define p (make-party))
  (pop! p) ; displays "Boom! 108"
  (push! p (push (make 5 5) 1))
  (pop! p)) ; displays "Boom! 24"

; de-import all libraries
(import)

; erase the party library from flash (re-list all libs to check)
(erase -1)

; erase all libs from flash (00.0241-style, re-list all libs to check)
(erase -536870912)

; erase all libs from flash (00.0250-style, re-list all libs to check)
(erase-libs)



 

Runge-Kutta:


The code below is the Runge-Kutta solution of a system of Ordinary Differential Equations (ODEs) representing a simple oscillator that is given on page 44 of the Revised^5 Report on the Algorithmic Language Scheme (r5rs). A helper function to drive the code is given at the end. This example is the same as in all prior versions of Armpit Scheme.



; Armpit Scheme Runge-Kutta Example (R5RS p. 44)
; Tested on Tiny2138, SFE-Logomatic, LPC-H2148, LCDDemo-2158, Tiny2106,
;           LPC-H2214, SAM7-H256, STR-H711, LPC-H2888, CS-E9302,
;           LM3S1968-EVB, TI-Beagle

(define integrate-system
  (lambda (system-derivative initial-state h)
    (let ((next (runge-kutta-4 system-derivative h)))
      (letrec ((states
		(cons initial-state
		      (delay (map-streams next states)))))
	states))))

; There is no need to paste this in two chunks to avoid errors anymore
(define runge-kutta-4
  (lambda (f h)
    (let ((*h (scale-vector h))
	  (*2 (scale-vector 2))
	  (*1/2 (scale-vector (/ 1 2)))
	  (*1/6 (scale-vector (/ 1 6))))
      (lambda (y)
	(let* ((k0 (*h (f y)))
	       (k1 (*h (f (add-vectors y (*1/2 k0)))))
	       (k2 (*h (f (add-vectors y (*1/2 k1)))))
	       (k3 (*h (f (add-vectors y k2)))))
	  (add-vectors
	   y (*1/6 (add-vectors k0 (*2 k1) (*2 k2) k3))))))))

(define elementwise
  (lambda (f)
    (lambda vectors
      (generate-vector
       (vector-length (car vectors))
       (lambda (i)
	 (apply f
		(map (lambda (v) (vector-ref v i))
		     vectors)))))))

(define generate-vector
  (lambda (size proc)
    (let ((ans (make-vector size)))
      (letrec ((loop
		(lambda (i)
		  (cond ((= i size) ans)
			(else
			 (vector-set! ans i (proc i))
			 (loop (+ i 1)))))))
	(loop 0)))))

(define add-vectors (elementwise +))

(define scale-vector
  (lambda (s)
    (elementwise (lambda (x) (* x s)))))

(define map-streams
  (lambda (f s)
    (cons (f (head s))
	  (delay (map-streams f (tail s))))))

(define head car)

(define tail
  (lambda (stream) (force (cdr stream))))

(define damped-oscillator
  (lambda (R L C)
    (lambda (state)
      (let ((Vc (vector-ref state 0))
	    (I1 (vector-ref state 1)))
	(vector (- 0 (+ (/ Vc (* R C)) (/ I1 C)))
		(/ Vc L))))))

(define the-states
  (integrate-system
   (damped-oscillator 10000 1000 .001)
   '#(1 0)
   .01))

; function to compute the solution for a given time span
(define oscillate
  (lambda (steps)
    (let loop ((n steps) (r the-states))
      (and (>= n 0)
	   (write (- steps n))
	   (write (head r))
	   (newline)
	   (loop (- n 1) (tail r))))))

; compute the solution
(oscillate 10)

(oscillate 50)

(oscillate 100)



 

Runge-Kutta Library:


The code below is the library version of the Runge-Kutta example presented above. It is adapted from the library example presented in Appendix D of the r6rs. The code has been modified from the r6rs example to use delay/force as in the r5rs example rather than lambdas (as in the r6rs example) because the former leads to markedly faster execution in the ArmPit Scheme interpreter (the same was observed in guile 1.7.1 for a non-library based implementation). It is the same as in the previous release except for the use of (libs), now part of the core (but a reverse order listing relative to 00.0241 functions).



; Armpit Scheme Runge-Kutta Library Example (R6RS Appendix D)
; Tested on SFE-Logomatic V2.0


; build the runge-kutta library
(library
 (runge-kutta)
 (export integrate-system head tail)
 (import)
 ;; library body
 (define integrate-system
  (lambda (system-derivative initial-state h)
    (let ((next (runge-kutta-4 system-derivative h)))
      (letrec ((states
		(cons initial-state
		      (delay (map-streams next states)))))
	states))))
 (define runge-kutta-4
   (lambda (f h)
     (let ((*h (scale-vector h))
	   (*2 (scale-vector 2))
	   (*1/2 (scale-vector (/ 1 2)))
	   (*1/6 (scale-vector (/ 1 6))))
       (lambda (y)
	 ;; y is a system state
	 (let* ((k0 (*h (f y)))
		(k1 (*h (f (add-vectors y (*1/2 k0)))))
		(k2 (*h (f (add-vectors y (*1/2 k1)))))
		(k3 (*h (f (add-vectors y k2)))))
	   (add-vectors y
			(*1/6 (add-vectors k0
					   (*2 k1)
					   (*2 k2)
					   k3))))))))
 (define elementwise
   (lambda (f)
     (lambda vectors
       (generate-vector
	(vector-length (car vectors))
	(lambda (i)
	  (apply f
		 (map (lambda (v) (vector-ref v i))
		      vectors)))))))
 (define generate-vector
   (lambda (size proc)
     (let ((ans (make-vector size)))
       (letrec ((loop
		 (lambda (i)
		   (cond ((= i size) ans)
			 (else
			  (vector-set! ans i (proc i))
			  (loop (+ i 1)))))))
	 (loop 0)))))
 (define add-vectors (elementwise +))
 (define scale-vector
   (lambda (s)
     (elementwise (lambda (x) (* x s))))) 
(define map-streams
  (lambda (f s)
    (cons (f (head s))
	  (delay (map-streams f (tail s)))))) 
 (define head car)
(define tail
  (lambda (stream) (force (cdr stream)))))

; list all libraries (as a check, 00.0241-style)
(map (lambda (e) (list (vector-ref (vector-ref e 0) 0))) (vector-ref (_GLV) 12))

; list all libraries (as a check, 00.0250-style)
(libs)

; import the runge-kutta library
(import (runge-kutta))

(define damped-oscillator
  (lambda (R L C)
    (lambda (state)
      (let ((Vc (vector-ref state 0))
	    (Il (vector-ref state 1)))
	(vector (- 0 (+ (/ Vc (* R C)) (/ Il C)))
		(/ Vc L))))))

(define the-states
  (integrate-system
   (damped-oscillator 10000 1000 .001)
   '#(1 0)
   .01))

; function to compute the solution for a given time span
(define oscillate
  (lambda (steps)
    (let loop ((n steps) (r the-states))
      (and (>= n 0)
	   (write (- steps n))
	   (write (head r))
	   (newline)
	   (loop (- n 1) (tail r))))))

; compute the solution
(oscillate 10)

(oscillate 50)

(oscillate 100)



 

Fast Fourier Transform:


The code below provides two examples of Fast Fourier Transform computation in Armpit Scheme 00.0250. The examples are the same as in the previous snapshot. The first example is adapted for complex numbers from the FFT example provided in the Gambit-C Scheme benchmarks here, and side-effects the input data vector. The second example is adapted from a Scheme Workshop entry by John David Stone and preserves the input data vector.




; Armpit Scheme FFT Example
; Tested on SFE-Logomatic V2.0


; Example 1: FFT adapted from Gambit-C Scheme benchmarks
; modified for complex numbers

; define pi
(define pi (* 4 (atan 1)))

; forward FFT function
(define (four2 data)
  (let ((n (vector-length data)))
    (let loop1 ((i 0) (j 0))
      (if (< i n)
        (begin
          (if (< i j)
              (let ((temp (vector-ref data i)))
                (vector-set! data i (vector-ref data j))
                (vector-set! data j temp)))
          (let loop2 ((m (bitwise-arithmetic-shift n -1)) (j j))
            (if (and (>= m 2) (>= j m))
              (loop2 (bitwise-arithmetic-shift m -1) (- j m))
              (loop1 (+ i 1) (+ j m)))))))
    (let loop3 ((mmax 1))
      (if (< mmax n)
	  (let ((wp (- (make-polar 1 (/ pi mmax)) 1)))
	    (let loop4 ((w 1.0) (m 0))
	      (if (< m mmax)
		  (begin
		    (let loop5 ((i m))
		      (if (< i n)
			  (let* ((j (+ i mmax))
				 (temp (* w (vector-ref data j))))
			    (vector-set! data j (- (vector-ref data i) temp))
			    (vector-set! data i (+ (vector-ref data i) temp))
			    (loop5 (+ j mmax)))))
		    (loop4 (+ (* w wp) w) (+ m 1)))))
	    (loop3 (* mmax 2)))))))

; simple data set, 32 real values
(define data
  (let ((d (make-vector 32)))
    (let loop ((n 0))
      (if (> n 31) d
	  (begin
	    (vector-set! d n (+ 1/3 (cos (* (/ 2 32) 2 pi n))))
	    (loop (+ n 1)))))))

; forward transform --  this side-effects data
(four2 data)

; view result
data


;  Example 2: FFT adapted from Scheme Workshop code by John David Stone

; define pi
(define pi (* 4 (atan 1)))

(define fft
  (let ((unshuffle
         (lambda (seq)
           (let loop ((rest seq)
                      (evens '())
                      (odds '()))
             (if (null? rest)
                 (cons (reverse evens) (reverse odds))
                 (loop (cddr rest)
                       (cons (car rest) evens)
                       (cons (cadr rest) odds)))))))
    (lambda (sequence)
      (let ((len (length sequence)))
        (if (= len 1)
            sequence
            (let ((nth-root (make-polar 1 (/ (* 2 pi) len)))
                  (half-len (quotient len 2))
                  (packs (unshuffle sequence)))
              (let loop ((step 0)
                         (root 1)
                         (evens (fft (car packs)))
                         (odds (fft (cdr packs)))
                         (front '())
                         (rear '()))
                (if (= step half-len)
                    (append (reverse front) (reverse rear))
                    (loop (+ step 1)
                          (* root nth-root)
                          (cdr evens)
                          (cdr odds)
                          (cons (+ (car evens) (* root (car odds)))
                                front)
                          (cons (- (car evens) (* root (car odds)))
                                rear))))))))))

; simple data set, 32 real values
(define data2
  (let ((d (make-vector 32)))
    (let loop ((n 0))
      (if (> n 31) (vector->list d)
	  (begin
	    (vector-set! d n (+ 1/3 (cos (* (/ 2 32) 2 pi n))))
	    (loop (+ n 1)))))))

; perform FFT
(fft data2)

; get magnitude of Fourier components
(map magnitude (fft data2))


 

Expert System:


This Expert System example is the same as in previous snapshots except that, relative to 00.0241, it uses the built-in defined? function (re-instated from 00.0215).




; Armpit Scheme Expert System Example
; Tested on SFE-Logomatic V2.0

; utility function for printed output
(define (writeln . expr)
  (display-all expr))

; utility function for printed output
(define (display-all lst)
  (if (null? lst)
      (newline)
      (begin
	(display (car lst))
	(display-all (cdr lst)))))

; initial function that defines what to do when query fails
(define (fail) #f)

; current depth of chaining over rules
(define chain-depth 0)

; function to delay evaluation of alternatives
(define (cdelay fn)
  (let ((hold-fail fail))
    (set! fail
	  (lambda ()
	    (set! fail hold-fail)
	    (fn)))))

; function to pick one of several alternatives
(define (amb . expr-list)
  (call/cc
   (lambda (return)
     (for-each
      (lambda (expr)
	(cdelay (lambda () (return expr))))
      expr-list)
     (fail))))

; helper macro to temporarily set the value of a variable
(define-syntax set
  (syntax-rules ()
    ((_ var val)
     (let ((local-save var))
       (cdelay (lambda () (set! var local-save) (amb)))
       (set! var val)))))

; function to temporarily set the value of a variable
(define (bind! var expr)
  (eval `(set ,var ',expr)))

; function to identify whether a variable is bound
; uses (interaction-environment) to define 'new' vars
(define (bound? var)
  (or (defined? var)
      (eval `(define ,var 'UNASSIGNED) (interaction-environment)))
  (not (eq? (eval var) 'UNASSIGNED)))

; function to identify whether an expression is a variable
(define (variable? expr)
  (and
   (symbol? expr)
   (eq? #\?
	(string-ref (symbol->string expr) 0))))

; function to identify whether an expression is a rule
(define (rule? expr)
  (and (pair? expr)
       (equal? (cadr expr) ':-)))

; function to substitute variable-bindings into an expression
(define (subst-bindings form)
  (cond ((pair? form)
	 (cons (subst-bindings (car form))
	       (subst-bindings (cdr form))))
	((variable? form)
	 (if (bound? form)
	     (subst-bindings (eval form))
	     form))
	(else form)))

; function to unify two expressions
(define (unify pattern1 pattern2)
  (cond
   ((equal? pattern1 pattern2) #t)
   ((and (pair? pattern1) (pair? pattern2))
    (and
     (unify (car pattern1) (car pattern2))
     (unify (cdr pattern1) (cdr pattern2))))
   ((variable? pattern1)
    (if (bound? pattern1)
	(unify (eval pattern1) pattern2) 
	(and 
	 (no-self-ref? pattern1 pattern2)
	 (bind! pattern1 pattern2))))
   ((variable? pattern2)
    (unify pattern2 pattern1))
   (else (amb))))

; function to identify whether self-references exist in an expression
(define (no-self-ref? var expr) 
  (cond ((equal? var expr) (amb))
	((pair? expr)
	 (and (no-self-ref? var (car expr)) 
	      (no-self-ref? var (cdr expr))))
	((variable? expr)
	 (or (not (bound? expr))
	     (no-self-ref? var (eval expr))))
	(else #t)))

; function to evaluate a knowledge-base query
(define (qeval query kb)
  (or (eq? query #t)
      (let ((kb-item (apply amb kb)))
	(if (rule? kb-item)
	    (let ((clean-rule (rename-vars kb-item)))
	      (unify query (car clean-rule))
	      (set chain-depth (+ 1 chain-depth))
	      (and-query (cddr clean-rule) kb))
	    (unify query kb-item)))))

; function to evaluate an and query
(define (and-query pattern-list kb)
  (or (null? pattern-list)
      (and (qeval (car pattern-list) kb)
	   (and-query (cdr pattern-list) kb))))

; function to rename the variables in an expression
(define (rename-vars expr)
  (cond
   ((pair? expr)
    (cons
     (rename-vars (car expr))
     (rename-vars (cdr expr))))
   ((variable? expr)
    (string->symbol
     (string-append
      (symbol->string expr)
      (number->string chain-depth))))
   (else expr)))

; function to find all true resolutions of a query
(define (all query . kbase)
  (let ((kb (if (null? kbase) *knowledge-base* (car kbase))))
    (and (qeval query kb)
	 (writeln (subst-bindings query))
	 (amb))))

; a basic fact base for testing
(define *fact-base*
  '((parent john joe)
    (parent john jim)
    (parent julie joe)
    (parent jill jim)
    (parent julie john)
    (parent jim  bill)
    (parent jim  jill)
    (parent joe alice)
    (parent joe linda)
    (male john)
    (male joe)
    (male jim)
    (male bill)
    (female jill)
    (female julie)
    (female alice)
    (female linda)))

; a basic rule base for testing
(define *rule-base*
  '(((mother ?x ?y) :- (female ?x) (parent ?x ?y))
    ((father ?x ?y) :- (male ?x) (parent ?x ?y))
    ((daughter ?x ?y) :- (female ?x) (parent ?y ?x))
    ((son ?x ?y) :- (male ?x) (parent ?y ?x))
    ((grandparent ?x ?z) :- (parent ?x ?y) (parent ?y ?z))
    ((grandmother ?x ?z) :- (mother ?x ?y) (parent ?y ?z))
    ((grandfather ?x ?z) :- (father ?x ?y) (parent ?y ?z))))

; define the knowledge base used for testing
(define *knowledge-base*
  (append *fact-base* *rule-base*))

; examples of basic queries
(all '(father ?x ?y))

(all '(father ?x ?x))

(all '(mother ?x ?y))

(all '(parent ?x joe))

(all '(grandparent ?x alice))

(all '(grandfather ?x alice))

(all '(grandfather ?x linda))

(all '(?x jim ?y))

(all '(grandparent ?x ?x))

(all '(son ?x ?y))

(all '(son jim ?x))

(all '(son ?x jim))

(all '(daughter ?x joe))

(all '(?x ?y ?z)) ; find every ternary relation that can be infered


 

ARMSchembler and Compiler Libraries:


The ARMSchembler presented here is a mild update of that of snapshot 00.0241. The sub-libraries in which it is partitioned were adjusted to be loadable on more MCUs (eg. LPC-1768) and functionality to allow immutable primitives to be considered (in view of the re-worked system core) was developed (pldr macro). it is still designed to be loaded from an SD card, using SD functions that are now built into the core, and it is to be used with the linker that is also in the 00.0250 core.

After copying the ARMSchembler source file to a SD card on your development system, place the card in an ArmPit Scheme system, reset it (if desired or needed), initialize the SD sub-system (if needed) and install the ARMSchembler:
     ap> (sd-init)                    ; check for #t or #vu8(...), redo if #f  (not needed on OMAP3530)
     ap> (load "asar0250.scm" SDFT)   ; for ARM  (omit SDFT on OMAP3530 Live-SD)
     ap> (libs)                       ; check for (as) ... to verify installation

OR:
     ap> (sd-init)                    ; check for #t or #vu8(...), redo if #f  (not needed on OMAP3530)
     ap> (load "asT20250.scm" SDFT)   ; for Cortex-M3 (Thumb2)
     ap> (libs)                       ; check for (as) ... to verify installation

The Compiler for ArmPit Scheme (caps) library is also a mild update of the compiler for 00.0241. The main modifications are the way the immutable-primitives flag is processed and the partitioning of sub-libraries: It is designed to be copied to an SD card and then installed on an ArmPit Scheme system using:
     ap> (load "caps0250.scm" SDFT)  ; all architectures  (omit SDFT on OMAP3530 Live-SD)
     ap> (libs)                      ; check for (caps) ... to verify installation

ARMSchembler and Compiler initialization and tests are presented here:



Last updated June 17, 2011

bioe-hubert-at-sourceforge.net