Skip to content

Commit

Permalink
Initial commit; successfully blinks an LED.
Browse files Browse the repository at this point in the history
  • Loading branch information
lonetech committed Mar 23, 2015
1 parent 790b6b3 commit 53dd97a
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#MCU=msp430f5510
# MCU is now defined in msp403.nim

NIMFLAGS=-d:release --os:standalone --opt:size --gc:none --deadCodeElim:on
# avr is the closest cpu for the moment
NIMFLAGS+=--cpu:avr
# running one C compiler lets its errors show
NIMFLAGS+=--parallelBuild:1 --verbosity:1

%: %.nim panicoverride.nim
nim c $(NIMFLAGS) $<

blink: blink.nim msp430usb.nim msp430.nim

all: blink

# Uses python-msp430-tools
program: blink
python -m msp430.bsl5.hid -e $^
40 changes: 40 additions & 0 deletions blink.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import msp430
#import msp430usb

# Trivial blink demo for now.

template toggleLED() =
PJ.OUT = PJ.OUT xor 8

proc main =
PJ.DIR = PJ.DIR or 8
while true:
toggleLED()
var i {.volatile.} = 0x7350 # volatile to keep delay loop
while i!=0:
i = i - 1

main()


# My first project is a PC joystick to USB adapter based on an
# Olimexino-5510 board (a MSP430 board resembling an Arduino Pro).
# Judging by the SW/HW I2C solder jumpers on the board, the
# designer was unaware that this chip can remap those functions.
# I intend to measure the analog resistances by timing a capacitor
# charge, similar to the original card. Luckily the f5510 has
# more than four timer capture pins for this.
# I also intend to add a Gravis Grip decoder, for which the
# pin change interrupts will come in handy.
# Pins connected on adapter board so far:
# 1,8,9,15 5v
# 4,5,12 gnd
# 7 b2 d3 ta0_0
# 6 y1 d4 ta0_1 needs capacitor
# 14 b3 d2 p1_0
# 13 y2 d5 ta0_2 needs capacitor
# 11 x2 d6 ta0_3 needs capacitor
# 3 x1 d7 ta0_4 needs capacitor
# pins yet to connect
# 2 b1 d8 p1_6
# 10 b4 d9 p1_7
71 changes: 71 additions & 0 deletions msp430.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import macros

const mcu="msp430f5510"

{.passC: "-mmcu="&mcu.}
{.passL: "-mmcu="&mcu.}

type
GPIO = tuple
IN: int16
OUT: int16
DIR: int16
REN: int16
DS: int16
SEL: int16
# Only port A (aka port 1 and 2) has interrupts
IES: int16
IE: int16
IFG: int16

macro declGPIO(n: expr): stmt {.immediate.} =
result = newNimNode(nnkStmtList)
n.expectKind(nnkIdent)
let name = $n.ident
# Doing it this way sadly leaves parsing modules (parseutils, strutils,
# macros) which have initializers in the runtime (empty, but each wastes
# six words). But building the expression directly is awfully clumsy.
# This makes me see more appeal to lisp.
result.add(parseStmt("var "&name&"IN {.header: \"<msp430.h>\", importc.} : int16"),
parseStmt("template "&name&"*: expr = cast[ptr GPIO](addr "&name&"IN)"))

var
WDTCTL* {.header: "<msp430.h>", importc.} : int16

declGPIO(PA)
declGPIO(PJ)

template setPragma(node: stmt, name: string, value: string) =
if node.pragma.kind==nnkEmpty:
node.pragma=newNimNode(nnkPragma)
node.pragma.add(newNimNode(nnkExprColonExpr)
.add(newIdentNode(name))
.add(newStrLitNode(value)))
template setPragma(node: stmt, name: string) =
if node.pragma.kind==nnkEmpty:
node.pragma=newNimNode(nnkPragma)
node.pragma.add(newIdentNode(name))

macro ISR*(procs: stmt): stmt {.immediate.} =
# Statement macro that modifies a proc to work as interrupt handler
# The vectors are only resolved at C level, so this routine does not
# need to know which exist.
let keeps = newNimNode(nnkStmtList)
# TODO: parse the C header file to extract numbers like these
for node in procs.children:
node.expectKind(nnkProcDef)
let name : string = $node.name.ident
node.setPragma("codegenDecl", "$# __attribute__((__interrupt__("&name&"_VECTOR))) $# $#")
node.setPragma("exportc", "ISR_" & name)
keeps.add(newNimNode(nnkDiscardstmt).add(node.name))
# discard statements are generated to keep the proc referenced
# dead code elimination doesn't know of the ISR vector table
result = procs.add(keeps)

# Example usage
#ISR:
# proc SYSNMI() =
# return

# Disable watchdog timer
WDTCTL = 0x5a80
103 changes: 103 additions & 0 deletions msp430usb.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import msp430


type
USBVECINT_value = enum
NONE = 0x00
PWR_DROP = 0x02
PLL_LOCK = 0x04
PLL_SIGNAL = 0x06
PLL_RANGE = 0x08
PWR_VBUSOn = 0x0A
PWR_VBUSOff = 0x0C
USB_TIMESTAMP = 0x10
INPUT_ENDPOINT0 = 0x12
OUTPUT_ENDPOINT0 = 0x14
RSTR = 0x16
SUSR = 0x18
RESR = 0x1A
SETUP_PACKET_RECEIVED = 0x20
STPOW_PACKET_RECEIVED = 0x22
INPUT_ENDPOINT1 = 0x24
INPUT_ENDPOINT2 = 0x26
INPUT_ENDPOINT3 = 0x28
INPUT_ENDPOINT4 = 0x2A
INPUT_ENDPOINT5 = 0x2C
INPUT_ENDPOINT6 = 0x2E
INPUT_ENDPOINT7 = 0x30
OUTPUT_ENDPOINT1 = 0x32
OUTPUT_ENDPOINT2 = 0x34
OUTPUT_ENDPOINT3 = 0x36
OUTPUT_ENDPOINT4 = 0x38
OUTPUT_ENDPOINT5 = 0x3A
OUTPUT_ENDPOINT6 = 0x3C
OUTPUT_ENDPOINT7 = 0x3E

var
USBVECINT* {.header: "<msp430.h>", importc.} : USBVECINT_value

ISR:
proc USB_UBM() =
while true:
# computedGoto does not seem to understand the values are all even
# {.computedGoto.}
case USBVECINT
of NONE:
return
of PWR_DROP:
PA.OUT = 4
of PLL_LOCK:
PA.OUT = 5
of PLL_SIGNAL:
PA.OUT = 6
of PLL_RANGE:
PA.OUT = 7
of PWR_VBUSOn:
PA.OUT = 1
of PWR_VBUSOff:
PA.OUT = 2
of USB_TIMESTAMP:
PA.OUT = 8
of INPUT_ENDPOINT0:
PA.OUT = 9
of OUTPUT_ENDPOINT0:
PA.OUT = 9
of RSTR:
PA.OUT = 9
of SUSR:
PA.OUT = 9
of RESR:
PA.OUT = 9
of SETUP_PACKET_RECEIVED:
PA.OUT = 9
of STPOW_PACKET_RECEIVED:
PA.OUT = 9
of INPUT_ENDPOINT1:
PA.OUT = 9
of INPUT_ENDPOINT2:
PA.OUT = 9
of INPUT_ENDPOINT3:
PA.OUT = 9
of INPUT_ENDPOINT4:
PA.OUT = 9
of INPUT_ENDPOINT5:
PA.OUT = 9
of INPUT_ENDPOINT6:
PA.OUT = 9
of INPUT_ENDPOINT7:
PA.OUT = 9
of OUTPUT_ENDPOINT1:
PA.OUT = 9
of OUTPUT_ENDPOINT2:
PA.OUT = 9
of OUTPUT_ENDPOINT3:
PA.OUT = 9
of OUTPUT_ENDPOINT4:
PA.OUT = 9
of OUTPUT_ENDPOINT5:
PA.OUT = 9
of OUTPUT_ENDPOINT6:
PA.OUT = 9
of OUTPUT_ENDPOINT7:
PA.OUT = 9

4 changes: 4 additions & 0 deletions nim.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# We use the AVR target for msp430, since Nim sees it as a 16-bit
# little endian target (which is more true of msp430 than avr).
avr.standalone.gcc.exe = "msp430-gcc"
avr.standalone.gcc.linkerexe = "msp430-gcc"
20 changes: 20 additions & 0 deletions panicoverride.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

#proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}

{.push stack_trace: off, profiler:off.}

proc rawoutput(s: string) =
#printf("%s\n", s)
return

proc panic(s: string) =
#rawoutput(s)
exit(1)

# Alternatively we also could implement these 2 here:
#
# template sysFatal(exceptn: typeDesc, message: string)
# template sysFatal(exceptn: typeDesc, message, arg: string)

{.pop.}

0 comments on commit 53dd97a

Please sign in to comment.