parent
02ac1e2e4f
commit
97c0fb8e4a
@ -1,3 +1,3 @@ |
||||
across |
||||
stellaris |
||||
msp430/mecrisp |
||||
/across |
||||
/stellaris |
||||
/msp430/mecrisp |
||||
|
@ -1 +0,0 @@ |
||||
../../sbo-l041/board.fs |
@ -0,0 +1,68 @@ |
||||
\ on_top_of always.fs |
||||
\ board definitions |
||||
|
||||
eraseflash |
||||
compiletoflash |
||||
( board start: ) here dup hex. |
||||
|
||||
include ../../flib/mecrisp/hexdump-min.fs |
||||
include ../../flib/stm32l0/io-min.fs |
||||
include ../../flib/pkg/pins20.fs |
||||
include ../../flib/stm32l0/hal-min.fs |
||||
include ../../flib/stm32l0/sleep-min.fs |
||||
include ../../flib/stm32l0/adc-min.fs |
||||
|
||||
PA1 constant LED \ sbo active low |
||||
\ PB3 constant LED \ nucleo32 active high |
||||
PB1 constant BTN \ -1 pressed, 0 not |
||||
|
||||
: led-off LED ios! ; |
||||
: led-on LED ioc! ; |
||||
|
||||
PA4 variable ssel |
||||
PA5 constant SCLK |
||||
PA6 constant MISO |
||||
PA7 constant MOSI |
||||
include ../../flib/stm32l0/spi-min.fs |
||||
\ rf69 rf-rssi needs LED |
||||
include ../../flib/spi/rf69-min.fs |
||||
|
||||
PA9 constant SCL |
||||
PA10 constant SDA |
||||
\ potentially messes up PA0-PA5 as well |
||||
: i2c-pafs $110 PA9 io-base $24 + ! ; \ (GPIO.AFRH) |
||||
include ../../flib/stm32l0/i2c-min.fs |
||||
|
||||
: sleep ( -- ) [ $BF30 h, ] inline ; \ WFI Opcode, enters sleep mode (systick wakes) |
||||
|
||||
: hello ( -- ) flash-kb . ." KB <n041> " hwid hex. |
||||
$8000 compiletoflash here - flashvar-here compiletoram here - |
||||
." ram/flash: " . . ." free " ; |
||||
|
||||
: init ( -- ) \ board initialisation |
||||
init \ uses new uart init convention |
||||
%10001100 $4002102C bic! \ disable ioports C D H (RCC-IOPENR) |
||||
OMODE-PP LED io-mode! |
||||
IMODE-FLOAT BTN io-mode! |
||||
\ 16MHz ( set by Mecrisp on startup to get an accurate USART baud rate ) |
||||
8 $4002104C ! \ set USART2 clock to HSI16, independent of sysclk (sbo uses USART2!!) (RCC-CCIPR) |
||||
1000 systick-hz |
||||
led-on |
||||
hello ." ok." cr |
||||
; |
||||
|
||||
: rx-connected? ( -- f ) \ true if RX is connected (and idle) |
||||
IMODE-LOW PA3 io-mode! sleep PA3 io@ 0<> OMODE-AF-PP PA3 io-mode! |
||||
dup if sleep serial-key? if serial-key drop then then \ flush any input noise |
||||
; |
||||
|
||||
: fake-key? ( -- f ) \ check for RX pin being pulled high |
||||
rx-connected? if reset then false ; |
||||
|
||||
: unattended |
||||
rx-connected? if quit then \ return to command prompt |
||||
['] fake-key? hook-key? ! ; |
||||
|
||||
( board end, size: ) here dup hex. swap - . |
||||
cornerstone <<<board>>> |
||||
compiletoram |
@ -0,0 +1,3 @@ |
||||
include always.fs |
||||
include board.fs |
||||
include main.fs |
@ -1,7 +0,0 @@ |
||||
<<basis>> |
||||
compiletoflash |
||||
include g2553/spi.fs |
||||
include drivers/rf69.fs |
||||
include g2553/i2c-bb-base.fs |
||||
include drivers/i2c-bb.fs |
||||
reset |
@ -1,3 +1,5 @@ |
||||
The 'lowpower' version needs an external 32768Hz crystal between P2.6 and P2.7 (pins 19 and 18 on MSP430G2553) - because the delays in this one are done with low power sleep, and waking up needs a timer, which needs this external source. |
||||
|
||||
The 'xt1' versions also need an external 32768Hz crystal on the correct pins; this time with loading caps as well. |
||||
|
||||
The current `.hex` files are all with mecrisp-2.0.6a. |
||||
|
@ -1,12 +0,0 @@ |
||||
: i2c. ( -- ) \ scan and report all I2C devices on the bus |
||||
128 0 do |
||||
cr i h.2 ." :" |
||||
16 0 do space |
||||
i j + |
||||
dup $08 < over $77 > or if drop 2 spaces else |
||||
dup i2c-addr 0 i2c-xfer if drop ." --" else h.2 then |
||||
then |
||||
loop |
||||
16 +loop ; |
||||
|
||||
|
@ -0,0 +1,11 @@ |
||||
\ on_top_of basis-g2553.fs |
||||
|
||||
<<basis>> |
||||
compiletoflash |
||||
|
||||
include spi.fs |
||||
include ../drivers/rf69.fs |
||||
include i2c-bb-base.fs |
||||
include ../drivers/i2c-bb.fs |
||||
|
||||
reset |
@ -0,0 +1,13 @@ |
||||
\ MSP430G2553 Launchpad-specific words |
||||
|
||||
compiletoflash |
||||
|
||||
: init init |
||||
8 $21 cbis! \ High (P1OUT) |
||||
8 $27 cbis! \ Pullup for button (P1REN) |
||||
1 64 or $21 cbic! \ LEDs off (P1OUT) |
||||
1 64 or $22 cbis! \ LEDs are outputs (P1DIR) |
||||
\ P1.6 is output: if not, launchpad power consumption goes up by 20uA |
||||
; |
||||
|
||||
compiletoram |
@ -0,0 +1,11 @@ |
||||
\ spi.tmplfill: template filler for spi driver |
||||
\ compile into constant-free file with |
||||
\ python templates/replace_constants.py templates/g2553-spi.fs g2553/spi.tmplfill g2553/usci-regs.fs g2553/port-regs.fs |
||||
|
||||
1 constant SPIPIN |
||||
P2OUT constant SPIOUT |
||||
P2DIR constant SPIDIR |
||||
P2IN constant SPIIN |
||||
P1SEL constant SPISEL |
||||
P1SEL2 constant SPISEL2 |
||||
%11100000 constant SPISELBITS |
@ -0,0 +1,33 @@ |
||||
\ USCI registers |
||||
\ G2553 datasheet, p19 |
||||
|
||||
$001 constant IE2 |
||||
$003 constant IFG2 |
||||
|
||||
%0001 constant IFG2_UCA0RXIFG |
||||
%0010 constant IFG2_UCA0TXIFG |
||||
%0100 constant IFG2_UCB0RXIFG |
||||
%1000 constant IFG2_UCB0TXIFG |
||||
|
||||
$05D constant UCA0ABCTL |
||||
$05E constant UCA0IRTCTL |
||||
$05F constant UCA0IRRCTL |
||||
$060 constant UCA0CTL0 |
||||
$061 constant UCA0CTL1 |
||||
$062 constant UCA0BR0 |
||||
$063 constant UCA0BR1 |
||||
$064 constant UCA0MCTL |
||||
$065 constant UCA0STAT |
||||
$066 constant UCA0RXBUF |
||||
$067 constant UCA0TXBUF |
||||
|
||||
$068 constant UCB0CTL0 |
||||
$069 constant UCB0CTL1 |
||||
$06A constant UCB0BR0 |
||||
$06B constant UCB0BR1 |
||||
$06C constant UCB0CIE |
||||
$06D constant UCB0STAT |
||||
$06E constant UCB0RXBUF |
||||
$06F constant UCB0TXBUF |
||||
$118 constant UCB0OA |
||||
$11A constant USB0SA |
@ -0,0 +1,29 @@ |
||||
\ MSP430(G2553) SPI driver |
||||
\ uses USCI_B0 (P1.5 SCK, P1.6 MISO, P1.7 MOSI) {because USCI_A0 is used for USART} |
||||
\ (c) 2019 flabbergast |
||||
|
||||
: +spi ( -- ) SPIPIN SPIOUT cbic! ; \ select SPI |
||||
: -spi ( -- ) SPIPIN SPIOUT cbis! ; \ deselect SPI |
||||
|
||||
: >spi> ( c -- c ) \ hardware SPI, 1 byte in, 1 byte out |
||||
begin IFG2_UCB0TXIFG IFG2 bit@ until \ TXbuf ready? |
||||
$6F c! \ send byte (UCB0TXBUF) |
||||
begin IFG2_UCB0RXIFG IFG2 bit@ until \ RXbuf ready? |
||||
UCB0RXBUF c@ \ read byte |
||||
; |
||||
|
||||
\ single byte shortcuts |
||||
: spi> ( -- c ) 0 >spi> ; \ read byte from SPI |
||||
: >spi ( c -- ) >spi> drop ; \ write byte to SPI |
||||
|
||||
: spi-init ( -- ) \ set up hardware SPI |
||||
-spi SPIPIN SPIDIR cbis! \ setup CS pin |
||||
SPISELBITS SPISEL cbis! \ setup SCK|MISO|MOSI pins |
||||
SPISELBITS SPISEL2 cbis! \ setup SCK|MISO|MOSI pins |
||||
1 UCB0CTL1 c! \ put USCI in reset (UCSWRST) |
||||
%10101001 UCB0CTL0 c! \ 3-pin 8-bit SPI master (UCCKPH|UCMSB|UCMST|UCSYNC) |
||||
%11000000 UCB0CTL1 cbis! \ clock source SMCLK (UCSSELx) |
||||
2 UCB0BR0 c! 0 UCB0BR1 c! \ prescaler /8 |
||||
1 UCB0CTL1 cbic! \ init USCI (UCSWRST) |
||||
; |
||||
|
@ -0,0 +1,40 @@ |
||||
\ rf69 driver constants |
||||
|
||||
$00 constant RF:FIFO |
||||
$01 constant RF:OP |
||||
$07 constant RF:FRF |
||||
$11 constant RF:PA |
||||
$18 constant RF:LNA |
||||
$1F constant RF:AFC |
||||
$24 constant RF:RSSI |
||||
$27 constant RF:IRQ1 |
||||
$28 constant RF:IRQ2 |
||||
$2F constant RF:SYN1 |
||||
$31 constant RF:SYN3 |
||||
$39 constant RF:ADDR |
||||
$3A constant RF:BCAST |
||||
$3C constant RF:THRESH |
||||
$3D constant RF:PCONF2 |
||||
$3E constant RF:AES |
||||
|
||||
%00000 constant RF:M_SLEEP |
||||
%00100 constant RF:M_STDBY |
||||
%01000 constant RF:M_FS |
||||
%01100 constant RF:M_TX |
||||
%10000 constant RF:M_RX |
||||
|
||||
$C2 constant RF:START_TX |
||||
$42 constant RF:STOP_TX |
||||
$80 constant RF:RCCALSTART |
||||
|
||||
%10000000 constant RF:IRQ1_MRDY |
||||
%01000000 constant RF:IRQ1_RXRDY |
||||
%00001000 constant RF:IRQ1_RSSI |
||||
%00000100 constant RF:IRQ1_TIMEOUT |
||||
%00000001 constant RF:IRQ1_SYNC |
||||
|
||||
%01000000 constant RF:IRQ2_FIFO_NE |
||||
%00001000 constant RF:IRQ2_SENT |
||||
%00000100 constant RF:IRQ2_RECVD |
||||
%00000010 constant RF:IRQ2_CRCOK |
||||
|
@ -0,0 +1,162 @@ |
||||
\ rf69 driver; this file contains both tx and rx parts (splittable) |
||||
\ - slightly modified version of a pretty smart jcw's driver: |
||||
\ https://git.jeelabs.org/jcw/embello |
||||
\ - mainly some 32 vs 16 bit fixes |
||||
\ - frequency is hardcoded and non-correctable |
||||
\ - for the names of registers and bits see the fancy driver |
||||
\ needs spi |
||||
\ generate constant-free source with: |
||||
\ python replace-constants.py rf69.fs rf69-constants.fs |
||||
\ = 1762 bytes in flash |
||||
|
||||
\ TX part |
||||
|
||||
0 variable rf.mode \ last set chip mode |
||||
0 variable rf.last \ flag used to fetch RSSI only once per packet |
||||
0 variable rf.rssi \ RSSI signal strength of last reception |
||||
66 buffer: rf.buf \ buffer with last received packet data |
||||
|
||||
42 variable rf.group \ network group (1..250) |
||||
61 variable rf.nodeid \ node ID of this node (1..63) |
||||
|
||||
create rf:init \ initialise the radio, each 16-bit word is <reg#,val> |
||||
hex |
||||
0200 , \ packet mode, fsk |
||||
0302 , 048A , \ bit rate 49,261 hz |
||||
0505 , 06C3 , \ 90.3kHzFdev -> modulation index = 2 |
||||
07D9 , 0813 , 0900 , \ 868.3MHz frequency ( freq[Hz] * 2^19 / 32*10^6, MSB ) |
||||
0B20 , \ low M |
||||
1942 , 1A42 , \ RxBw 125khz, AFCBw 125khz |
||||
1E0C , \ AFC auto-clear, auto-on |
||||
2607 , \ disable clkout |
||||
29C4 , \ RSSI thres -98dB |
||||
2B40 , \ RSSI timeout after 128 bytes |
||||
2D05 , \ Preamble 5 bytes |
||||
2E90 , \ sync size 3 bytes |
||||
2FAA , \ sync1: 0xAA -- this is really the last preamble byte |
||||
302D , \ sync2: 0x2D -- actual sync byte |
||||
312A , \ sync3: network group |
||||
37D0 , \ drop pkt if CRC fails \ 37D8 h, \ deliver even if CRC fails |
||||
3842 , \ max 62 byte payload |
||||
3C8F , \ fifo thres |
||||
3D12 , \ PacketConfig2, interpkt = 1, autorxrestart on |
||||
6F20 , \ Test DAGC |
||||
7102 , \ RegTestAfc |
||||
0 , \ sentinel |
||||
decimal align |
||||
|
||||
\ r/w access to the RF registers |
||||
: rf!@ ( b reg -- b ) +spi >spi >spi> -spi ; |
||||
: rf! ( b reg -- ) $80 or rf!@ drop ; |
||||
: rf@ ( reg -- b ) 0 swap rf!@ ; |
||||
|
||||
: rf-h! ( h -- ) dup $FF and swap 8 rshift rf! ; |
||||
|
||||
: rf!mode ( b -- ) \ set the radio mode, and store a copy in a variable |
||||
dup rf.mode ! |
||||
RF:OP rf@ $E3 and or $01 rf! |
||||
begin RF:IRQ1 rf@ RF:IRQ1_MRDY and until ; |
||||
|
||||
: rf-config! ( addr -- ) \ load many registers from <reg,value> array, zero-terminated |
||||
RF:M_STDBY rf!mode \ some regs don't program in sleep mode, go figure... |
||||
begin dup @ ?dup while rf-h! 2+ repeat drop |
||||
; |
||||
|
||||
: rf-group ( u -- ) RF:SYN3 rf! ; \ set the net group (1..250) |
||||
|
||||
: rf-check ( b -- ) \ check that the register can be accessed over SPI |
||||
begin dup RF:SYN1 rf! RF:SYN1 rf@ over = until |
||||
drop ; |
||||
|
||||
: rf-ini ( group -- ) \ internal init of the RFM69 radio module |
||||
spi-init |
||||
$AA rf-check $55 rf-check \ will hang if there is no radio! |
||||
rf:init rf-config! |
||||
rf-group ; |
||||
|
||||
: rf-parity ( -- u ) \ calculate group parity bits |
||||
RF:SYN3 rf@ dup 4 lshift xor dup 2 lshift xor $C0 and ; |
||||
|
||||
: rf-n@spi ( addr len -- ) \ read N bytes from the FIFO |
||||
0 do RF:FIFO rf@ over c! 1+ loop drop ; |
||||
: rf-n!spi ( addr len -- ) \ write N bytes to the FIFO |
||||
0 do dup c@ RF:FIFO rf! 1+ loop drop ; |
||||
|
||||
\ this is the intended public API for the RF69 driver |
||||
|
||||
: rf-power ( n -- ) \ change TX power level (0..31) |
||||
RF:PA rf@ $E0 and or RF:PA rf! ; |
||||
|
||||
: rf-sleep ( -- ) RF:M_SLEEP rf!mode ; \ put radio module to sleep |
||||
|
||||
: rf-encrypt ( addr -- ) \ load 16 bytes as AES password, enable encryption |
||||
RF:AES 16 + RF:AES do \ loop by register addr |
||||
dup c@ dup i rf! \ write one, leave ( addr b ) |
||||
if 1+ then \ if b <> 0, advance addr |
||||
loop drop |
||||
RF:PCONF2 rf@ 1 or RF:PCONF2 rf! ; |
||||
|
||||
: rf-deencrypt ( -- ) \ clear encryption |
||||
RF:PCONF2 rf@ $FE and RF:PCONF2 rf! ; |
||||
|
||||
: rf-send ( addr count hdr -- ) \ send out one packet |
||||
RF:M_STDBY rf!mode |
||||
over 2+ RF:FIFO rf! |
||||
dup rf-parity or RF:FIFO rf! |
||||
$C0 and rf.nodeid @ or RF:FIFO rf! |
||||
( addr count ) rf-n!spi |
||||
RF:M_TX rf!mode |
||||
begin RF:IRQ2 rf@ RF:IRQ2_SENT and until |
||||
RF:M_STDBY rf!mode ; |
||||
|
||||
: rf-init ( -- ) \ init RFM69 with current rf.group |
||||
rf.group @ rf-ini ; |
||||
|
||||
: rf-info ( -- ) \ display reception parameters as hex string |
||||
rf.group @ h.2 rf.rssi @ h.2 ; |
||||
|
||||
|
||||
\ RX part |
||||
|
||||
\ rf-timeout checks whether there is an rssi timeout and restarts the receiver if so. |
||||
: rf-timeout ( -- ) |
||||
RF:IRQ1 rf@ RF:IRQ1_TIMEOUT and if |
||||
RF:M_FS rf!mode |
||||
then ; |
||||
|
||||
\ rf-status fetches the IRQ1 reg, checks whether rx_sync is set and was not set |
||||
\ in rf.last. If so, it saves rssi value; and then updates rf.last. |
||||
\ rf.last ensures that the info is grabbed only once per packet. |
||||
: rf-status ( -- ) \ update status values on sync match |
||||
RF:IRQ1 rf@ RF:IRQ1_SYNC and rf.last @ <> if |
||||
rf.last RF:IRQ1_SYNC over xor! @ if |
||||
RF:RSSI rf@ rf.rssi ! |
||||
then |
||||
then ; |
||||
|
||||
\ this is the intended public API for the RF69 driver |
||||
|
||||
: rf-recv ( -- b ) \ check whether a packet has been received, return #bytes |
||||
rf.mode @ RF:M_RX <> if |
||||
0 rf.rssi ! |
||||
RF:M_RX rf!mode |
||||
else rf-timeout rf-status then |
||||
RF:IRQ2 rf@ RF:IRQ2_CRCOK and if |
||||
RF:FIFO rf@ 66 min \ fetch length and limit |
||||
rf.buf over rf-n@spi |
||||
else 0 then ; |
||||
|
||||
: rf-ack? ( ms -- b ) \ waits ms milliseconds for an ACK and returns #bytes recv'd |
||||
0 rf.rssi ! |
||||
RF:M_RX rf!mode |
||||
0 do |
||||
rf-status \ capture rssi, etc. |
||||
RF:IRQ2 rf@ RF:IRQ2_CRCOK and if |
||||
RF:FIFO rf@ 66 min \ fetch length and limit |
||||
rf.buf over rf-n@spi |
||||
unloop exit |
||||
then |
||||
1 ms |
||||
loop |
||||
RF:M_STDBY rf!mode \ kill RX |
||||
0 ; |
@ -0,0 +1,35 @@ |
||||
#!/usr/bin/env python3 |
||||
|
||||
import os |
||||
import argparse |
||||
|
||||
|
||||
def print_file(abspath,ontop=False,depth=0): |
||||
(dirname,filename) = os.path.split(abspath) |
||||
beginnote = ' '*4*depth + '\ {{{ ' + ('='*5*(depth+1)) + ' included %s%s =====\n' |
||||
endnote = ' '*4*depth + '\ }}} ' + ('='*5*(depth+1)) + ' end of included %s =====\n' |
||||
with open(abspath) as f: |
||||
for line in f: |
||||
if line.startswith('include '): |
||||
newfile = line.split()[1] |
||||
print(beginnote % ('', os.path.basename(newfile))) |
||||
print_file(os.path.abspath(os.path.join(dirname,newfile)),ontop=ontop,depth=depth+1) |
||||
print(endnote % os.path.basename(newfile)) |
||||
elif ontop and line.startswith('\\ on_top_of'): |
||||
newfile = line.split()[2] |
||||
print(beginnote % ('(on_top_of) ', os.path.basename(newfile))) |
||||
print_file(os.path.abspath(os.path.join(dirname,newfile)),ontop=ontop,depth=depth+1) |
||||
print(endnote % os.path.basename(newfile)) |
||||
else: |
||||
print(' '*4*depth + line.rstrip()) |
||||
|
||||
|
||||
argparser = argparse.ArgumentParser(description='Recursively replace ''include'' in forth sources by contents. No files changed, output will be send to stdout.') |
||||
argparser.add_argument('file', help='File to start with') |
||||
argparser.add_argument('-o', '--on_top_of', action='store_true', help='Resolve also "\ on_top_of"') |
||||
#argparser.add_argument('definitions', nargs='*', help='Where to read the constants from') |
||||
args = argparser.parse_args() |
||||
|
||||
print_file(args.file,ontop=args.on_top_of,depth=0) |
||||
|
||||
print('\n\ vim: filetype=forth:foldmethod=marker:') |
Loading…
Reference in new issue