First Foray into KiCad

KiCad is a free software tool for designing Printed Circuit Boards, and can generate files to use with services like PCBWay. PCB manufacturing is getting so cheap now that it is hard to justify all the time and bother of old-fashioned soldering in a project with more than a dozen traces.

KiCad is a bit intimidating at first because of the many pages of the manual and tutorials, and a large forest of minor details. But I think it is not so scary once you understand the basic workflow:

1 – Put together a schematic. This shows the basic types of components (“symbols”) in your circuit and how they interconnect.

Somewhat embarrassing first schematic using KiCad.

2 – Assign “footprints” to your symbols. Footprints basically are the actual hardware you want to match to the component type.

3 – Use the new PCB tool to generate a PCB based on your schematic. You need (in a simple design) to lay out the traces and ground plane on your front and back copper layers, and then lay out the shape of your board in the edge cut layer.

Simple PCB design in KiCad

You can then view the PCB in 3D view if you wish.

Simple PCB design in 3D View

One hundred dollars in Monopoly money to the first person who can figure out what that circuit does!

And finally you generate Gerber files, which can be submitted to a service like PCBWay. You pay for the service, and they send the board with traces, holes, pads, labeling, and artwork as specified. You get the components separately and solder those on yourself.

First Foray into FlashForth for AVR

Arduino-FVM was a nice, easy introduction to Forth on AVR/Arduino, and has a few advantages as a Forth implementation. But I was interested in something more developed and full-featured. So today I got FlashForth installed on a 328P MC, running on an Arduino Uno.

Installing FlashForth on AVR requires setting fuse bits as well as burning a new flash image, so I had to wire up my Nano ArduinoISP programmer again. Pulling this off required mixing details from the ArduinoISP tutorial, my previous post on ArduinoISP, and instructions from the FlashForth Web site, none of which were quite sufficient information taken individually.

I used the precompiled 328P hex flash image that is included in the FlashForth git repo. I intend at some point to compile the source, but I needed to get over the initial hurdle of seeing if I could get FlashForth to run on an MC at all, and if I liked it. This was the avrdude call which worked for me:

christopher@theoden ~/Repos/flashforth/avr/hex$ avrdude -p m328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -e -u -U flash:w:328-16MHz-38400.hex:i -U efuse:w:0xff:m -U hfuse:w:0xda:m -U lfuse:w:0xff:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: erasing chip
avrdude: reading input file "328-16MHz-38400.hex"
avrdude: writing flash (32524 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 32524 bytes of flash written
avrdude: verifying flash memory against 328-16MHz-38400.hex:
avrdude: load data flash data from input file 328-16MHz-38400.hex:
avrdude: input file 328-16MHz-38400.hex contains 32524 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 32524 bytes of flash verified
avrdude: reading input file "0xff"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xff:
avrdude: load data efuse data from input file 0xff:
avrdude: input file 0xff contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of efuse verified
avrdude: reading input file "0xda"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xda:
avrdude: load data hfuse data from input file 0xda:
avrdude: input file 0xda contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xff"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xff:
avrdude: load data lfuse data from input file 0xff:
avrdude: input file 0xff contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified

avrdude done.  Thank you.

Here is the logon using picocom:

christopher@theoden ~/Repos/flashforth/avr/hex$ picocom -b 38400 -c /dev/ttyACM0picocom v3.1

port is        : /dev/ttyACM0
flowcontrol    : none
baudrate is    : 38400
parity is      : none
databits are   : 8
stopbits are   : 1
escape is      : C-a
local echo is  : yes
noinit is      : no
noreset is     : no
hangup is      : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv -E
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,
logfile is     : none
initstring     : none
exit_after is  : not set
exit is        : no

Type [C-a] [C-h] to see available commands
Terminal ready
E FlashForth 5 ATmega328 18.11.2020

Here are the words defined by default:

words 
p2+ pc@ @p hi d. ud. d> d< d= d0< d0= dinvert d2* d2/ d- d+ dabs ?dnegate dnegate s>d rdrop endit next for in, inline repeat while again until begin then else if zfl pfl xa> >xa x>r dump .s words >pr .id ms ticks r0 s0 latest state bl 2- ['] -@ ; :noname : ] [ does> postpone create cr [char] ihere ( char ' lit abort" ?abort ?abort? abort prompt quit true false .st inlined immediate shb interpret 'source >in tiu tib ti# number? >number ud/mod ud* sign? digit? find immed? (f) c>n n>c @+ c@+ place cmove word parse \ /string source user base pad hp task ulink rsave bin hex decimal . u.r u. sign #> #s # digit <# hold up min max ?negate tuck nip / u*/mod u/ * u/mod um/mod um* 'key? 'key 'emit p++ p+ pc! p! p@ r>p !p>r !p u> u< > < = 0< 0= <> within +! 2/ 2* >body 2+ 1- 1+ negate invert xor or and - m+ + abs dup r@ r> >r rot over swap drop allot ." ," s" (s" type accept 1 umax umin spaces space 2swap 2dup 2drop 2! 2@ cf, chars char+ cells cell+ aligned align cell c, , here dp ram eeprom flash >< rp@ sp@ 2constant constant 2variable variable @ex execute key? key emit Fcy mtst scan skip n= rshift lshift mclr mset ic, i, operator iflush cwd wd- wd+ pause turnkey to is defer value fl+ fl- c! c@ @ a> ! >a literal int! ;i di ei ver warm empty rx0? rx0 tx0 load- load+ busy idle exit 
marker  ok<#,ram>

I only had a few minutes to experiment with it, but here are a several things of interest:

  • One great thing about FlashForth is that all the three memory types – RAM, flash, and EEPROM, are mapped to a contiguous address space, and accessible with @ and ! memory words. So, you don’t have to do anything special to write to flash or EEPROM.
  • By default, all words you add to the dictionary are compiled to flash memory and therefore survive a chip reset. This is very convenient.
  • You are not actually allowed to redefine words (at least, in the usual way of defining words), but you are expected instead to use the marker Forth word to construct forgettable sections of words. Also the empty word will remove all words but the core FlashForth words.

ANSI Cursor Control from Forth

ANSI graphics in the kitty terminal emulator

When lacking a bit-mapped graphics interface, one old standby is ANSI cursor control, which allows 8 colors, with cursor positioning assuming a monospace font. It could allow you to do limited graphics and forms over a UART connection, e.g., the serial connection to a microcontroller.

An entertaining rabbit trail: Here is Emacs running the pong game in an X11 window (i.e., normal graphics):

Emacs Pong using normal X11 graphics

But if you run Emacs in no-window mode (i.e., “terminal” mode) it looks like it falls back to control codes (ANSI escape codes…?)

Emacs Pong using terminal graphics (control codes, I presume)

Emacs was designed originally to be run in terminal environments which used control codes — bit-mapped graphics were later grafted on to Emacs. This allows Emacs to be run from a Gnu/Linux virtual console (e.g., CTRL-ALT-F2).

Anyway, here is a Forth interface to some of the ANSI escape codes, specifically line,column cursor positioning, and setting a graphics mode (character attributes like color and bold/underline).

\ Copyright 2020 Christopher Howard

\ ansi-cursor.fs

\ Licensed under the Apache License, Version 2.0 (the "License");
\ you may not use this file except in compliance with the License.
\ You may obtain a copy of the License at

\     http://www.apache.org/licenses/LICENSE-2.0

\ Unless required by applicable law or agreed to in writing, software
\ distributed under the License is distributed on an "AS IS" BASIS,
\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\ See the License for the specific language governing permissions and
\ limitations under the License.

\ http://ascii-table.com/ansi-escape-sequences.php

\ GFX mode values

30 constant black-fg
31 constant red-fg
32 constant green-fg
33 constant yellow-fg
34 constant blue-fg
35 constant magenta-fg
36 constant cyan-fg
37 constant white-fg

40 constant black-bg
41 constant red-bg
42 constant green-bg
43 constant yellow-bg
44 constant blue-bg
45 constant magenta-bg
46 constant cyan-bg
47 constant white-bg

0 constant attributes-off
1 constant bold
4 constant underscore
5 constant blink
7 constant reverse
8 constant concealed

: <esc> 0x1b emit ;

: <[> [char] [ emit ;

: .| abs 0 <# #s #> type ;

: <;> [char] ; emit ;

: position-cursor ( line col -- ) <esc> <[> swap .| <;> .| [char] H emit ;

: erase-display <esc> <[> 2 .| [char] J emit ;

: set-gfx-mode ( gfx-mode-value -- )
    <esc> <[> .| [char] m emit ;

And demo example code:

\ Copyright 2020 Christopher Howard

\ demo.fs

\ Licensed under the Apache License, Version 2.0 (the "License");
\ you may not use this file except in compliance with the License.
\ You may obtain a copy of the License at

\     http://www.apache.org/licenses/LICENSE-2.0

\ Unless required by applicable law or agreed to in writing, software
\ distributed under the License is distributed on an "AS IS" BASIS,
\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\ See the License for the specific language governing permissions and
\ limitations under the License.

require ansi-cursor.fs

: exp-scale ( n prescaled-range scaled-range -- n )
    rot dup * * swap dup * / ;

: cab-dist ( x y xc yc -- n ) 2 pick - abs >r swap drop - abs r> + ;

: demo-scale ( x y xc yx unscaled-range )
    >r cab-dist r> 8 exp-scale 7 min ;

: demo attributes-off set-gfx-mode erase-display
    80 0 do
        40 0 do
            i j 2dup position-cursor
            20 40 70 demo-scale black-bg + set-gfx-mode
            space
        loop
    loop
    attributes-off set-gfx-mode
    20 31 position-cursor ." * ansi-cursor demo *"
    40 0 position-cursor
;

Successful (?) Read from the PCI Bus Configuration

Trying to access PCI bus configuration on Lenovo T60 laptop from BYOK Forth

It looks like if I’m going to get the AHCI SATA access I want, then I’m going to have to learn how to interact with the PCI bus. And I wanted to interact with the bus from Forth itself, rather than having to debug C code. First baby step: to see if I could pull any information from a PCI bus configuration register.

This seems to be fairly simple in principle: configuration access is port-based, with a 32 bit address memory location (CONFIG ADDRESS), and a 32 bit data memory location (CONFIG DATA). Put the correct request information in CA, and pull the data from CD. https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231.

The tricky part: since this is I/O memory, you have to access it using the Pentium INL and OUTL instructions. BYOK had implemented INB and OUTB, but these are not quite the instructions we wanted, and also they weren’t mapped to Forth words. But thankfully nice examples are available in a gcc library. So, I expanded BYOK’s io.h to…

static inline unsigned char inportb (uint16_t port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (port));
    return rv;
}

static inline void outportb (uint16_t port, unsigned char data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (port), "a" (data));
}

/* inport, outportl added by Christopher Howard 2020 */

static inline unsigned int inportl (unsigned short int port)
{
    unsigned int rv;
    __asm__ __volatile__ ("inl %w1, %0" : "=a" (rv) : "dN" (port));
    return rv;
}

static inline void outportl (unsigned int value, unsigned short int port)
{
    __asm__ __volatile__ ("outl %0, %w1" : : "a" (value), "dN" (port));
}

So, then I need to map this to Forth words, and I wasn’t sure where to do that. So, I added them to BYOK’s primitive word list. I wasn’t sure if the author of BYOK would have approved of that particular approach, but better to ask forgiveness later. Inserted the following into io.c:

state_t __INL(context_t *ctx)
{
    unsigned int port;
    if (popnum(ctx->ds, &port))
    {
        port = inportl (port);
        pushnum(ctx->ds, port);
        return OK;
    }
    else
    {
        return stack_underflow(ctx);
    }
}

state_t __OUTL(context_t *ctx)
{
    unsigned short int port;
    unsigned int value;
    if (popnum(ctx->ds, &port) && popnum(ctx->ds, &value))
    {
        outportl (value, port);
        return OK;
    }
    else
    {
        return stack_underflow(ctx);
    }
}

void init_io_words(context_t *ctx)
{
    hashtable_t *htbl = ctx->exe_tok;
    add_primitive(htbl, ".",      __DOT,    "( n -- )", "convert signed number n to string of digits, and output.");
 <...snip...>
    add_primitive(htbl, "INL",   __INL,   "( port -- )", "x86 32-bit read from i/o port");
    add_primitive(htbl, "OUTL",   __OUTL,   "( value port -- )", "x86 32-bit output to i/o port");
}

To my surprise, the code compiled. Now, I needed a Forth function to figure out what is the correct data to put into CA. This is the part I currently am manually typing into the laptop after boot:

hex

cf8 constant CA
cfc constant CD

: pci-cfg-word ( bus slot func offset -- u )
    -80000000
    swap fc and or
    swap 8 lshift or
    swap 11 lshift or
    swap 16 lshift or ;

decimal

In the laptop terminal I entered the following to get the (hopefully) correct address for CA on the stack, which is intended to pull the vendor code from the PCI bus:

0 0 0 0 pci-cfg-word
  ok...

Then load and read:

ca outl
  ok
cd inl
  ok.

Result in hexadecimal:

hex .s
27a08086

Is that information, or garbage? I found the PCI ID Repository on the Internet. If I make the reasonable assumption that the vendor code is in the 16 LSBs, that gives vendor code 0x8086, which matches to “Intel Corporation”. That sounds plausible!

Intel Corporation listing in The PCI ID Repository

Fun stuff!

Guix: List of Packages in Your Default Profile

(Some credit goes to the helpful folks in the #guix irc channel.)

If you are wanting to build a package manifest file, it is helpful to run code like in this example, which gives a list of packages in your profile by package name:

<username>@nightshade ~$ guix repl
GNU Guile 3.0.4
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guix-user)> ,use (guix profiles)
scheme@(guix-user)> (map manifest-entry-name (manifest-entries (profile-manifest "/home/<username>/.guix-profile")))
$1 = ("abbaye" "alex4" "astromenace" "audacity" "avr-toolchain" "bambam" "bombadillo" "bsd-games" "bzflag" "celestia-gtk" "chess" "corsix-th" "cool-retro-term" "cpupower" "curseradio" "dfu-programmer" "dosbox" "eboard" "edgar" "emacs" "emacs-arduino-mode" "emacs-doom-modeline" "emacs-doom-themes" "emacs-elpher" "emacs-geiser" "emacs-guix" "emacs-magit" "emacs-shell-pop" "emacs-spinner" "emacs-wget" "emacs-youtube-dl" "endless-sky" "file" "frozen-bubble" "ghex" "git" "gitg" "gforth" "glibc-locales" "gnome-shell-extensions" "gnucash" "gnupg" "gnuplot" "graphviz" "guile" "guile-colorized" "guile-hall" "guile-readline" "icedtea" "inkscape" "keepassxc" "kitty" "lm-sensors" "linphoneqt" "lure" "maxima" "meritous" "microscheme" "mps-youtube" "no-more-secrets" "openssh" "opensurge" "p7zip" "picocom" "pioneers" "qemu" "recutils" "screen" "starfighter" "stockfish" "strace" "supertux" "supertuxkart" "tig" "tree" "tuxpaint" "unzip" "warzone2100" "wget2" "wgetpaste" "wxmaxima" "xaos" "xboard" "xmoto" "xsensors" "youtube-dl" "youtube-viewer" "zip")

You can then copy and paste the list into a manifest file of this format:

(specifications->manifest '("abbaye" "alex4" ...etc... "zip"))

This is not quite a perfect conversion method as we have ignored some of the details of the profile entries like output type (e.g., out and utils). That could all be handled with some more guile scheme handling of the manifest entries, but I’m not feeling motivated to work out an example for this post.