Skip to content

kristianlm/chicken-debugwire

Repository files navigation

AVR debugWIRE library

This is a Chicken Scheme 5 library which lets you operate a AVR microcontroller using its on-board debugWIRE facility. It implements parts of the proprietary serial protocol, and exposes an API that allows you to:

  • Start and stop device CPU
  • Read and write device registers and SRAM
  • Read and write device flash memory
  • Execute arbitrary assembly instructions (16-bit opcodes only)

It’s based off of the wonderful work of RikusW, David C W Brown and Rafael G. Martins. The typical use of debugWIRE is indirectly through gdb, where the aforementioned projects shine. This library, however, takes a slightly different approach and tries to give you a Scheme REPL experience when working with these microcontrollers.

⚠ The project stage is experimental, at best! And only the ATtiny85 microcontroller is currently supported. If you actually just want to start with debugWIRE, I’d strongly recommend the projects above.

Getting started

You’ll need to enable debugWIRE on your target device. This means programming the DWEN bit, which you’ll probably have to do with the usual ICSP setup and then something like:

> avrdude -p attiny85 -U hfuse:w:0x9F:m

Once the target is debugWIRE-enabled, the RESET pin becomes available for debugWIRE commands. Pulling this line low for a few microseconds should give you the famous 0x55 greeting:

./images/debugwire-55-greeting.png

On can pull the line low manually, and then check for a 55 response on a scope before fighting UART drivers and baud rates. This fixed response can be used to detect the target baud rate (usually F_CPU / 64).

A prolonged low signal like this is an invalid serial frame. It’s called a break, hence the red ? on my scope. It’s used to, unsurprisingly, break the running target CPU. Once stopped, you can issue various commands like reading registers and executing ad-hoc instructions. This is where this library comes into play.

Please follow the hardware setup guide at dwire-debug for the UART setup. You’ll only need a good USB-UART adapter and a diode (plus something to enable debugWIRE). Your adapter needs to be able to generate a proper break signal and baudrates that match the target.

Example REPL session

> git clone chicken-debugwire && cd chicken-debugwire
> chicken-install .
> rlwrap csi

;; let's get ready
#;> (import avr.debugwire avr.asm chicken.blob)
#;> (dw-open! "/dev/ttyUSB1" (/ 4000000 64))
#;> (dw-break!)
dw-break-expect: serial read 85

;; CPU is now halted. let's have a look at register 24:
#;> (r 24)
0
#;> (set! (r 24) 100)
#;> (r 24)
100
#;> inc
#<procedure (inc d)>
#;> (inc 24)
#${8395}                  ;; <-- machine code / opcode for inc 24
#;> (dw-exec (inc 24))    ;; let's increment r24!
#;> (r 24)
101
#;> (dw-exec (inc 24))    ;; let's repeat this for sheer joy
#;> (r 24)
102

API

Not yet documented, sorry. Please read debugwire.scm. However, below are some of the getter-with-setter procedures. They expose various named variables of different sizes for convenience. They’re typically used like this: (r 0) or (set! (r 0) 255) to access r0.

namesizewheredescription
(PC)8dwaka Program Counter. Used/overwritten in various occations. Read immediately after dw-break! to get the “real” PC.
(BP)8dwaka Break-point. Used/overwritten in various places. Set to flash address before dw-continue* for “run to cursor”.
(IR)8dwaka Instruction register. Holds an arbitrary 16-bit opcode for immediate execution
(r x)8registerraw register access, where x is 0 - 31.
(X)16register(r 26) and (r 27)
(Y)16register(r 28) and (r 29)
(Z)16register(r 30) and (r 31)
(SP)16sramaka Stack Pointer.
(PINB)8sramPort B Input Pins Address (#x16)
(DDRB)8sramPort B Data Direction Register (#x17)
(PORTB)8sramPort B Data Register (#x18)

TODOs

This list would be seriously long for this library to turn into something of real-world value. So here are just a few major points:

Restoring target to working order before dw-continue

We not only mutate the debugWIRE registers like PC and BP, but we also mutate the on-target Z register when issuing sram-read etc. Therefore, we should keep track of the original values and restore them on dw-continue.

Address and register consistency

All assembly instructions just take in integers. We should probably introduce types here. It’s useful to know that an address is of type flash, we wouldn’t have to manually by two when working with rjmp etc.

Integration with avr-gcc and ELF debugging symbols

It’s be cool to be able to write C code the usual way, and have access to it’s symbol table from the REPL. This is in danger of reimplementing a little too much of gdb, though.

About

REPL-firendly debugWIRE library

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages