Proposed uLisp extension for writing to ports


#1

For some applications it would be convenient to the able to write an 8-bit byte to a port on the microcontroller in a single operation, or alternatively read a byte from a port. For example, I’m currently experimenting with interfacing an RGB LED Matrix Panel with uLisp which definitely needs something like this.

Existing options

Currently the only ways to do this are:

  • Write a loop calling digitalwrite eight times.

  • Write an assembler routine.

We need a way to read or write an entire byte from/to a port, or define all the bits in a port as outputs or inputs.

There was an earlier discussion about implementing something like this with peek and poke functions, named after the equivalents in BASIC: Adding your own functions. However I would prefer something that is more in the spirit of Lisp, and portable across different platforms.

Most microcontrollers group I/O pins together into ports, called A, B, C etc. Ideally it should be possible to write to a port from uLisp, without knowing the address of the port registers, just by referring to it as, for example, porta.

Proposal

To get the ball rolling here’s one suggestion:

The address of the port registers will be given for a particular processor by keywords; for example:

  • :porta-dir - direction register
  • :porta-out - output register
  • :porta-in - input register

A uLisp function, such as register, will read the port and return the value; for example:

(register :porta-in)

will return the byte on port A.

To write to a port we could either use a third parameter, so we could write:

(register :porta-out #xAA)

or take advantage of the in-place operations such as setf and write:

(setf (register :porta-out) #xAA)

To set the I/O lines on a port as outputs you would do:

(register :porta-dir #xFF)

or:

(setf (reg :porta-dir) #xFF)

Note that on AVR processors these functions would need to read and write the peripheral address space rather than the RAM address space.

Suggestions?


#2

Peek and poke are the fundamental operations. You can build the other interface on top of those operations, while the reverse is not true. (Indeed, the same is true for the various functions of the Wiring API.)

Moreover, I would argue that once you’re at the point where you’re manipulating things that directly you have almost definitely tied yourself to the specific hardware in other ways as well, so the low portability is less of an issue. It would be possible to provide device-specific uLisp definitions of the datasheet entries, in much the same way as programming on that level in C is usually done using manufacturer-provided header files.


#3

I think I’d prefer to offer more limited functionality, in a way that’s fairly portable, and without the dangers of being able to write anywhere in memory.


#4

Alternate suggestion:

 (in :port-a)
 (out :port-g value)

Just let the functions set the direction register as appropriate prior
to read/writing the value. This gives a higher level functionality to
the user ala BASIC of yore. The functions would return the value
read or written from/to the given port.

Just a thought…

-Rusty-


#5

I agree that’s a neater solution, but it’s not quite as flexible as it doesn’t allow you to write to an input port:

(register :porta-in #x80)

On most microcontrollers this lets you toggle bits in the port.

Also, you might want to read an output port, to check its current state:

(register :porta-out)