I/O

Mecrisp Ice supports both an I/O io@ and an I/O write io! command (Forth words). The words look much like the memory read :duref:@ and memory write ! words but they work a bit differently. For memory reads and writes, the address really is a 13/16/32/64 bit address. For I/O reads and writes, the 16 bit I/O address really represents one of 16 ports, each represented by a bit. This I/O model comes from the MSP430 chips. If you read the verilog, the io_addr wire really should be called the io_port wire. Here are some example of I/O ports.

Addr  Bit READ            WRITE

0001  0   PMOD in
0002  1   PMOD out        PMOD out
0004  2   PMOD dir        PMOD dir
0008  3   misc.out        misc.out

0010  4   header 1 in
0020  5   header 1 out    header 1 out
0040  6   header 1 dir    header 1 dir
0080  7

0100  8   header 2 in
0200  9   header 2 out    header 2 out
0400  10  header 2 dir    header 2 dir
0800  11

1000  12  UART RX         UART TX
2000  13  misc.in
4000  14  ticks           set ticks
8000  15

Contents of misc.out and misc.in

Bitmask Bit  misc.out        misc.in

  0001    0  SPI CS          UART Ready to Transmit
  0002    1  SPI MOSI        UART Character received
  0004    2  SPI SCK         SPI MISO
  0008    3  IrDA-TXD        IrDA-RXD
  0010    4  IrDA-Sleep      RTS
  0020    5  CTS             Random
  0040    6  Green LED
  0080    7  Red LED
  0100    8  Red LED
  0200    9  Red LED
  0400   10  Red LED

Of course the particular port mappings will depend on your specific board. Please read the README file in the directory for the board that you are using.

It makes sense for the software to be able to set individual bits. But when there is a transmission protocol, such as SPI, this appraoch is based on the Forth software bit banging the outputs. For example, for SPI, even the output clock gets bit banged!

  • The IN register gives the current electrical state

  • The contents of the OUT registers determine what level the outputs should be

  • The DIR register let you switch a pin to be an output by writing an one into

You can set two registers at once if you OR together their addresses.

255 $440 io! should set all header pins as outputs.

Inputs can be ORed together the same way and give an ORed result.

You can detect short-circuited pins

  • for example if a pin is set to output and low, but shortened to Vcc,

  • then the OUT register will read back low, as set by you, but the

  • IN register will read high for that pin.

Misc.out and misc.in are a mixed back of wires and flags available.

No fear to destroy the IrDA transceiver with too long pulses as it turns off the IR LED itself when IrDA-TXD is high for more than 50 us.

The UART data register is for both incoming and outgoing data, a read from it will clear the “Character received” flag and you should only write to it when “Ready to Transmit” is set.

Ticks contains a 16 bit cycle counter that counts up with 48 MHz and you can set it to any value you wish by writing to it.

Memory location $0002 is an interrupt vector for the ticks counter overflow. You can place an opcode there, perhaps ALU Exit ($608C) or a JMP to a handler. Interrupts can be enabled with eint and disabled with dint.