Have basic Low Speed SWIM read on the fly working.
Only reads one byte, but good enough.. to get things done. Code should actually work for low and high speed, but have only tested high speed on writes so far. Having issue where reads can fail at times. Esp with long strings of '0'.. Perhaps operating at high speed would improve matters.. Although I'm also realizing maybe I'm not waiting for the device to reset and reload HSI trim factory value, need to check that.. The new assembly file/function does everything needed so can start cutting out inline assembly from swim_out function. Swim code needs to run at 48Mhz. Realizing this is pretty vital to having enough time to handle high speed. And timing of artificial pull-up requires high trimmability..
This commit is contained in:
parent
0e0e307f64
commit
49b4639aa4
|
|
@ -65,6 +65,8 @@ CFLAGS+= $(DEFINE) $(INCLUDE)
|
|||
SOURCES=$(wildcard source/*.c source_stm_only/*.c)
|
||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||
|
||||
ASM_SRC=$(wildcard source/asm_stm/*.s)
|
||||
|
||||
#all: dir shared $(BUILD)/$(PROJ).axf $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
all: dir shared $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
|
||||
|
|
@ -72,10 +74,10 @@ all: dir shared $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin s
|
|||
# $@ is shortcut for the target, $^ is shortcut for prereqs
|
||||
# TARGET: PREREQS
|
||||
$(BUILD)/$(PROJ).axf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(CFLAGS) $(LFLAGS) -o $@
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).elf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(CFLAGS) $(LFLAGS) -o $@
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).hex: $(BUILD)/$(PROJ).elf
|
||||
$(OBJCOPY) -O ihex $^ $@
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ BASE=.
|
|||
|
||||
# Compiler & Linker
|
||||
CC=arm-none-eabi-gcc
|
||||
ASM=arm-none-eabi-as
|
||||
CXX=arm-none-eabi-g++
|
||||
OBJCOPY=arm-none-eabi-objcopy
|
||||
SIZE=arm-none-eabi-size
|
||||
|
|
@ -31,7 +32,7 @@ SIZE=arm-none-eabi-size
|
|||
ARCH_FLAGS=-mthumb -mcpu=cortex-m$(CORTEX_M)
|
||||
|
||||
# Startup code
|
||||
STARTUP=$(BASE)/include_stm/startup_ARM$(CORE).S
|
||||
STARTUP=$(BASE)/include_stm/startup_ARM$(CORE).S
|
||||
|
||||
# -Os -flto -ffunction-sections -fdata-sections to compile for code size
|
||||
CFLAGS=$(ARCH_FLAGS) $(STARTUP_DEFS) -Os -flto -ffunction-sections -fdata-sections -g
|
||||
|
|
@ -61,21 +62,23 @@ DEFINE+=\
|
|||
INCLUDE=-I ./include_stm
|
||||
CFLAGS+= $(DEFINE) $(INCLUDE)
|
||||
|
||||
#SOURCES=$(wildcard source/**/*.c source/*.c)
|
||||
SOURCES=$(wildcard source/*.c source_stm_only/*.c)
|
||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||
|
||||
ASM_SRC=$(wildcard source/asm_stm/*.s)
|
||||
|
||||
#all: dir shared $(BUILD)/$(PROJ).axf $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
all: dir shared $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
|
||||
#build axf file output (basically elf with DWARF debug info)
|
||||
# $@ is shortcut for the target, $^ is shortcut for prereqs
|
||||
# TARGET: PREREQS
|
||||
|
||||
$(BUILD)/$(PROJ).axf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(CFLAGS) $(LFLAGS) -o $@
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).elf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(CFLAGS) $(LFLAGS) -o $@
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).hex: $(BUILD)/$(PROJ).elf
|
||||
$(OBJCOPY) -O ihex $^ $@
|
||||
|
|
|
|||
|
|
@ -0,0 +1,514 @@
|
|||
|
||||
|
||||
//;Ensure that your assembly code complies with the Procedure Call Standard for the ARM Architecture (AAPCS).
|
||||
//;
|
||||
//;The AAPCS describes a contract between caller functions and callee functions. For example, for integer or pointer types, it specifies that:
|
||||
//;
|
||||
//; Registers R0-R3 pass argument values to the callee function, with subsequent arguments passed on the stack.
|
||||
//; Register R0 passes the result value back to the caller function.
|
||||
//; Caller functions must preserve R0-R3 and R12, because these registers are allowed to be corrupted by the callee function.
|
||||
//; Callee functions must preserve R4-R11 and LR, because these registers are not allowed to be corrupted by the callee function.
|
||||
//;
|
||||
//;For more information, see the Procedure Call Standard for the ARM Architecture (AAPCS).
|
||||
|
||||
//;WARNING!!! logic instructions all affect flags despite the 's' postfix arm_none_eabi_gcc doesn't like 's' instructions
|
||||
//; but the 's' affect flag instructions are the only ones the M0 supports
|
||||
//; because of this, issue the following code isn't compatible with other cores.
|
||||
|
||||
|
||||
.equ BSSR, 0x18
|
||||
.equ BRR, 0x28
|
||||
.equ OTYPER, 0x04
|
||||
.equ IDR, 0x10
|
||||
.equ NO_RESP, 0xFF
|
||||
.equ ACK, 0x01
|
||||
.equ NAK, 0x00
|
||||
.equ HERR, 0x0E
|
||||
.equ PERR, 0x09
|
||||
|
||||
.macro swim_lo
|
||||
strh swim_mask, [swim_base, #BRR]
|
||||
.endm
|
||||
.macro swim_hi
|
||||
strh swim_mask, [swim_base, #BSSR]
|
||||
.endm
|
||||
.macro swim_pp
|
||||
strh pushpull, [swim_base, #OTYPER]
|
||||
.endm
|
||||
.macro swim_od
|
||||
strh opendrain, [swim_base, #OTYPER]
|
||||
.endm
|
||||
|
||||
.equ SWIM_RD, 0x01
|
||||
.equ SWIM_WR, 0x02
|
||||
.equ SWIM_HS_BIT, 4
|
||||
.equ SWIM_HS_MSK, 0x10
|
||||
.equ HS_DELAY, 4
|
||||
.equ LS_DELAY, 22
|
||||
|
||||
.globl swim_xfr
|
||||
.p2align 2
|
||||
.type swim_xfr,%function
|
||||
//;r0 - r3 contain function args (excess on stack)
|
||||
//;swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
//;spddir_len = (SWIM_RD_LS<<16) | len;
|
||||
//; stream .req a1 this arg is moved to variable reg after stack push
|
||||
stream_arg .req a1
|
||||
rv .req r0
|
||||
len .req a2
|
||||
swim_base .req a3
|
||||
swim_mask .req a4
|
||||
swim_xfr: //;Function entry point.
|
||||
.fnstart
|
||||
|
||||
//;need a few extra variable registers, but they need to be preserved
|
||||
pushpull .req v1
|
||||
opendrain .req v2
|
||||
stream .req v3
|
||||
speed .req v4
|
||||
//;high registers r8-r12 are very limited following instructions can utilize them
|
||||
//; ADD, CMP, LDR PC-rel, BX, BLX, MSR, MSR
|
||||
//; Docs list that MOV can only use R0-7, but testing and compilation proves otherwise
|
||||
//; Additionally, arm_none_eabi_gcc uses MOV R8, R8 as it's NOP!!
|
||||
rdwr .req v5
|
||||
push {pushpull, opendrain, stream, speed, lr}
|
||||
mov speed, rdwr //;preserve r8 high register can't pop/push
|
||||
push {speed}
|
||||
|
||||
//; move stream arg out of r0, and into variable register so r0 is free
|
||||
mov stream, stream_arg
|
||||
|
||||
//; len contains speed and direction data, must trim off and move
|
||||
//; into variable registers
|
||||
//;spddir_len = (SWIM_RD/WR_LS/HS<<16) | len;
|
||||
mov r0, len
|
||||
lsr r0, #16
|
||||
cmp r0, #SWIM_HS_MSK
|
||||
bpl high_speed
|
||||
mov speed, #LS_DELAY
|
||||
b speed_dir
|
||||
high_speed:
|
||||
mov speed, #HS_DELAY
|
||||
speed_dir:
|
||||
//;mask out speed bit and store in rdwr
|
||||
//;shift speed bit left past carry
|
||||
lsl r0, #(16-SWIM_HS_BIT + 16) //;16-BIT shifts bit to b16, 16 shifts to carry = 28
|
||||
lsr r0, #(16-SWIM_HS_BIT + 16) //;carry doesn't shift in
|
||||
mov rdwr, r0
|
||||
|
||||
//; mask out upper bits of len
|
||||
mov r0, #0xFF
|
||||
and len, r0
|
||||
|
||||
|
||||
//; ~83nsec per unit of delay change
|
||||
//;mov speed, #22 //;22 = 2.75usec bit time delay variable
|
||||
//;mov speed, #4 //;4 = 1.25usec bit time delay variable
|
||||
//;mov speed, #22
|
||||
|
||||
//; set pushpull and opendrain to values we can write to otyper register
|
||||
//; to quickly change direction of the SWIM pin only
|
||||
ldr pushpull, [swim_base, #OTYPER]
|
||||
mov opendrain, pushpull
|
||||
//; variables hold current OTYPER register value
|
||||
//; set bit for opendrain, clear for pushpull
|
||||
orr opendrain, swim_mask
|
||||
bic pushpull, swim_mask
|
||||
|
||||
//; now these registers can be written directly to otyper GPIO reg
|
||||
//; to quickly change SWIM pin direction and not affect other pins
|
||||
|
||||
//;set flags so first bit is header '0' "from host"
|
||||
//;the stream comes in as 16bit value with stream bit 7 in bit position 15
|
||||
//;shift the stream left so the current transfer bit is in bit position 31
|
||||
//;15 -> 30 is 15bit shifts, this leaves header zero in bit position 31
|
||||
//;store stream in r4
|
||||
lsl stream, #15
|
||||
|
||||
|
||||
bit_start:
|
||||
|
||||
//;always start going low
|
||||
swim_lo
|
||||
|
||||
//;current bit is stored in bit31 and Negative flag is set if
|
||||
//;current bit is '1'
|
||||
bpl cur_bit_zero
|
||||
|
||||
//;delay to extend low time for '1'
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
//;go high since current bit is '1'
|
||||
swim_pp
|
||||
swim_hi
|
||||
swim_od
|
||||
b det_next_bit
|
||||
|
||||
cur_bit_zero:
|
||||
//;must delay same amount of time as instructions above since branch
|
||||
//;add delay here to make '0' longer until equal to '1'
|
||||
mov r0, #1
|
||||
bl delay_r0
|
||||
|
||||
det_next_bit:
|
||||
//;determine if this is the last bit
|
||||
sub len, #1
|
||||
|
||||
//;if last bit, go to stream end to prepare for ACK/NAK latch
|
||||
bmi out_end
|
||||
|
||||
//;delay until 'go high' time for '0'
|
||||
//;add delay here to make all bit transfers longer
|
||||
//;20-> 2.56usec bit time
|
||||
//;21-> 2.65usec
|
||||
//;22-> 2.73usec
|
||||
mov r0, speed ;//4-HS 22-LS
|
||||
bl delay_r0
|
||||
nop //;22+nop = 2.75usec = low speed timing perfect!
|
||||
|
||||
//; high speed bit time has same 0-high, 1-lo time
|
||||
//; only difference is bit time is 1.25usec
|
||||
|
||||
//;Negative flag is now set for '1', and clear for '0'
|
||||
//;always go high for '0' (no effect if already high for '1')
|
||||
swim_pp
|
||||
swim_hi
|
||||
swim_od
|
||||
|
||||
//;delay to extend high time of '0'
|
||||
nop
|
||||
nop
|
||||
|
||||
//;determine next bit value
|
||||
lsl stream, #1
|
||||
|
||||
//;go to bit start
|
||||
b bit_start
|
||||
|
||||
out_end:
|
||||
//;delay until 'go high' time for '0'
|
||||
mov r0, speed
|
||||
sub r0, #1 ;//this decrement keeps both HS and LS perfectly aligned
|
||||
bl delay_r0
|
||||
|
||||
//;always go high for '0' (no effect if already high for '1')
|
||||
swim_pp
|
||||
swim_hi
|
||||
swim_od
|
||||
|
||||
//;delay until time to latch ACK/NAK from device
|
||||
mov r0, #4 //;1-2:NR 3: usually RESP, not always/5-varies RESP/NO RESP
|
||||
//; sometime the device takes longer...
|
||||
//; 3 was failing for some, inc to 5
|
||||
//; 5 works, '1' NAK has low pulse width of 500-600nsec, trying 4
|
||||
//; 4 seems stable. low pulse time is 400-550nsec
|
||||
bl delay_r0
|
||||
|
||||
//;first need to ensure device is actually responding
|
||||
//;sample when output should be low for a 1 or 0
|
||||
//;appears the device inserts a little delay ~220nsec between final host bit
|
||||
//;and ACK/NAK
|
||||
//;total time between host high (parity bit = '0')
|
||||
//;and device ACK/NAK low is ~450nsec
|
||||
|
||||
//;debug toggle pushpull below
|
||||
//;measurements showed pulse ~100nsec after device took SWIM low with 3 above
|
||||
//;swim_pp
|
||||
//;swim_od
|
||||
|
||||
//;latch SWIM pin value from GPIO IDR
|
||||
ldrh rv, [swim_base, #IDR]
|
||||
and rv, swim_mask
|
||||
|
||||
|
||||
//;if it wasn't low, then the device didn't respond, so return error designating that
|
||||
//;__asm volatile ("bne no_response\n\t");
|
||||
beq wait_ack_nak
|
||||
|
||||
//;return 0xFF
|
||||
mov rv, #NO_RESP
|
||||
b exit_swim
|
||||
|
||||
wait_ack_nak:
|
||||
//;don't have a strong enough pull-up resistor on SWIM pin
|
||||
//;to compensate for this we can cheat by quickly toggling
|
||||
//;to push-pull after device should have gone high for ACK = '0'
|
||||
//;this does create bus contension for breif period but don't have much choice here..
|
||||
//;only other alternative is to install pullup on board/programmer
|
||||
//;swim_pp no delay_r0 outputs pulse ~240nsec after device goes low with 3 above
|
||||
//;swim_od
|
||||
|
||||
//; 3 above, and 2 here equates to pulse high 640nsec after device goes low
|
||||
//; 3 above, and 1 here equates to pulse high 460nsec after device goes low
|
||||
//; 3 above wasn't stable, incremented to 4 and works, give 400-550nsec pulse low
|
||||
//; mov r0, #1
|
||||
//; bl delay_r0
|
||||
;//r0=1: for ACK, artf pullup enabled 150-300nsec after device stops driving low
|
||||
;//this is okay timing allowance as being early would cause misread
|
||||
;//could possibly tighten with nops instead..
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop //;4 nops = 250-350nsec low pulse width for ACK '1'
|
||||
nop
|
||||
nop //;5 nops = 300-450nsec low pulse width
|
||||
swim_pp
|
||||
swim_od
|
||||
|
||||
//;now we can sample for NAK/ACK as artifical pullup has been inserted above
|
||||
//;if device output ACK, the artificial pullup doesn't cause contension
|
||||
//;but if device output NAK "0" device should still be driving low
|
||||
|
||||
//;latch SWIM pin value from GPIO IDR
|
||||
ldrh rv, [swim_base, #IDR]
|
||||
and rv, swim_mask
|
||||
|
||||
//; NAK: rv=0, ACK: rv=swim_mask
|
||||
beq return_nak
|
||||
|
||||
mov rv, #ACK
|
||||
//; device sent ACK, if this is a read operation
|
||||
//; need to capture data sent by the device
|
||||
mov stream, #SWIM_WR
|
||||
cmp rdwr, stream
|
||||
beq exit_swim
|
||||
|
||||
//; Sent the last byte of the command successfully
|
||||
//; Now read in data from device
|
||||
//; A bit of a challenge because of lacking legit pullup
|
||||
|
||||
//; setup for read transfer
|
||||
mov len, #9 //;read 9bits total, then output ACK
|
||||
|
||||
//; poll until device takes SWIM low for header bit
|
||||
//; perhaps setting an interrupt and waiting for it would be better
|
||||
//; due to less jitter from polling..
|
||||
poll_header:
|
||||
ldrh stream, [swim_base, #IDR]
|
||||
and stream, swim_mask
|
||||
bne poll_header
|
||||
|
||||
//;device took SWIM low
|
||||
//;pulse for artifical pullup
|
||||
mov r0, #1 //;1: 350-450nsec equates to 100-200nsec delay ~okay
|
||||
bl delay_r0
|
||||
|
||||
//;nop
|
||||
//;nop
|
||||
//;nop //; 3xnop = 250-300nsec low pulse for '1' header from device
|
||||
//;nop //; 4xnop = 250-350nsec
|
||||
//;nop //; 5xnop = 250-300 never seems to change!!!!
|
||||
|
||||
//; the device seems to stall for a little bit due to the delayed pull-up
|
||||
//; the bit time for the header seems to extend to ~3usec
|
||||
//; but perhaps we can take advantage of this to better align with the device
|
||||
//; add delay between here and read_next_bit to lengthen header bit
|
||||
|
||||
//; seemed to be a little early at times..
|
||||
swim_pp
|
||||
swim_od
|
||||
b read_next_bit
|
||||
|
||||
.p2align 4
|
||||
read_next_bit:
|
||||
swim_pp
|
||||
swim_od
|
||||
//; header bit '1' is now high
|
||||
|
||||
//; give a little delay between push pulse and reading
|
||||
//; this instruction can be performed out of order
|
||||
//; this didn't end up being a real problem, but it can't hurt
|
||||
lsl stream, #1
|
||||
|
||||
//; read bit, should be '1' for header on first read
|
||||
//; sample and place value in carry, then rotate in
|
||||
ldrh r0, [swim_base, #IDR]
|
||||
and r0, swim_mask
|
||||
//; Z flag contains inverse of bit
|
||||
mrs r0, APSR
|
||||
//; bit 30 of r0 contains inverse of bit
|
||||
//; shift left to mask away any upper bits
|
||||
lsl r0, #1
|
||||
//; shift right to mask away lower bits
|
||||
lsr r0, #31
|
||||
//; shift stream and or in r0 (stream does have mask bit set from poll loop)
|
||||
//; moved up to provide delay between push and read
|
||||
//;lsl stream, #1
|
||||
orr stream, r0
|
||||
//; now stream holds the inverse stream (plus mask junk on upper half)
|
||||
|
||||
|
||||
//; wait bit time, enable artifical pullup, and sample
|
||||
mov r0, speed
|
||||
sub r0, #2 //; need to save some delay for after pushing '0' high
|
||||
bl delay_r0
|
||||
|
||||
//; push high for logic '0'
|
||||
//;swim_pp
|
||||
//;swim_od
|
||||
//;mov r0, #2
|
||||
//;bl delay_r0
|
||||
|
||||
//; above isn't always getting SWIM pin high for '0'
|
||||
//; can only assume that it's too early
|
||||
swim_pp
|
||||
swim_od
|
||||
mov r0, #2
|
||||
bl delay_r0
|
||||
|
||||
//; seems to drop out at times..
|
||||
//; adding a check here to verify that SWIM is high looks like it would
|
||||
//; catch when the device drops out
|
||||
|
||||
//; check if last bit in read
|
||||
sub len, #1
|
||||
//;if last bit, go to stream end to prepare for ACK/NAK latch
|
||||
bpl read_next_bit
|
||||
|
||||
//; last bit calc and send parity, or just always send ACK
|
||||
//; could send back to poll header but not sure it's worth retrying..
|
||||
//; not sure a failure would even allow us to properly send a NAK
|
||||
|
||||
always_send_ack:
|
||||
//; ACK is a '1' from host, so need a short pulse low
|
||||
//; this is actually a little late, but seems the device sends it a little late as well
|
||||
//; so this happens to align pretty well with the device's timing
|
||||
swim_lo
|
||||
swim_pp
|
||||
mov r0, #1
|
||||
bl delay_r0
|
||||
swim_hi
|
||||
swim_od
|
||||
|
||||
//; organize return data
|
||||
//; MSB NAK/NORESP from last write
|
||||
//; if ACK, then return read result
|
||||
//; TIMEOUT, HEADER error, PAIRITY error
|
||||
//; ACK entire transfer good!
|
||||
//; LSB data read back
|
||||
|
||||
//; stream data sturcture
|
||||
//; upper bits may contain swim_mask value
|
||||
//; all values inverted:
|
||||
//; b9 header '1' -> '0'
|
||||
//; b8-1 data inverted 1's compliment
|
||||
//; b0 pairity inverted
|
||||
|
||||
//; write corrupted data for testing
|
||||
//; inverted 1 header bit - F0 data - 0 pairitybit
|
||||
//; 0 0F 1
|
||||
//; mov stream, #0x1F ;// good data should report 0xF0 - ACK
|
||||
//; mov stream, #0x1E ;// toggle pairity data should report PAIRITY ERROR
|
||||
|
||||
;// bad header data
|
||||
//; mov stream, #0x80
|
||||
//; mov rv, #2
|
||||
//; lsl stream, rv
|
||||
//; mov rv, #1 ;// set correct pairity
|
||||
//; orr stream, rv
|
||||
|
||||
//; store result as-is
|
||||
mov rv, stream
|
||||
|
||||
//; check that header was read as '1' (from device) and stored as '0'
|
||||
mov len, #0x80 ;// bad header data would have bit 9 set ('1' device header is inverted)
|
||||
mov swim_mask, #2
|
||||
lsl len, swim_mask ;// shift bit 7 into bit 9
|
||||
and stream, len
|
||||
//; should be zero if header stored as '0'
|
||||
bne header_error
|
||||
|
||||
//; calc pairity
|
||||
//; must add to registers to add with carry
|
||||
//; swim_mask no longer needed
|
||||
mov swim_mask, #0
|
||||
//; store stream temporarily in len reg while shifting pairity bit to carry
|
||||
lsr len, rv, #1
|
||||
|
||||
//; stream should be zero on entry
|
||||
//; add inverted pairity bit
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
//; add bit0-3
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
//; add bit4-7
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
lsr len, #1
|
||||
adc stream, swim_mask
|
||||
|
||||
//; individual sumation of all bits should be even when pairity included
|
||||
//; but for inverted data, the sum should be odd
|
||||
//; shift sum lsbit into carry and verify it's set (equates to odd)
|
||||
lsr stream, #1
|
||||
bcc pairity_error
|
||||
|
||||
//; all is good, just return the inverted data!
|
||||
lsr rv, #1
|
||||
//; mask out data alone
|
||||
mov len, #0xFF
|
||||
and rv, len
|
||||
//; invert data to true data
|
||||
eor rv, len
|
||||
|
||||
//; shift to upper byte
|
||||
lsl rv, #8
|
||||
//; add in the ACK to lower byte
|
||||
add rv, #ACK
|
||||
//; since things are little endian
|
||||
//; the output is a 16bit int
|
||||
//; so the value we output will be byte swapped
|
||||
//; when interpreted as 16bit int
|
||||
|
||||
b exit_swim
|
||||
|
||||
header_error:
|
||||
//; header wasn't '1' as expected when reading from device
|
||||
mov rv, #HERR
|
||||
b exit_swim
|
||||
|
||||
pairity_error:
|
||||
mov rv, #PERR
|
||||
b exit_swim
|
||||
|
||||
return_nak:
|
||||
mov rv, #NAK
|
||||
|
||||
exit_swim:
|
||||
//;r0 contains return value on exit (already done prior to this point)
|
||||
//;r4-r11 & lr must be preserved to entry values
|
||||
pop {speed}
|
||||
mov rdwr, speed //;restore r8 high register can't pop/push
|
||||
pop {pushpull, opendrain, stream, speed, pc}
|
||||
|
||||
//; bx lr //;Return by branching to the address in the link register.
|
||||
.fnend
|
||||
|
||||
|
||||
//;.globl delay_r0
|
||||
//; ~83nsec per unit of delay change
|
||||
.p2align 2
|
||||
.type delay_r0,%function
|
||||
count .req a1
|
||||
delay_r0: //;Function entry point.
|
||||
.fnstart
|
||||
sub count, #1
|
||||
bne delay_r0
|
||||
bx lr
|
||||
.fnend
|
||||
|
|
@ -22,6 +22,7 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
|
|||
#define RD_LEN 0
|
||||
#define RD0 1
|
||||
#define RD1 2
|
||||
uint16_t *ret_hword = (uint16_t*) &rdata[1];
|
||||
|
||||
#define BYTE_LEN 1
|
||||
#define HWORD_LEN 2
|
||||
|
|
@ -33,10 +34,13 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
|
|||
rdata[RD0] = swim_out( 0x0000, 4); break;
|
||||
case WOTF:
|
||||
rdata[RD_LEN] = BYTE_LEN;
|
||||
rdata[RD0] = swim_woft(operand, miscdata); break;
|
||||
// case ROTF:
|
||||
// rdata[RD_LEN] = BYTE_LEN;
|
||||
// rdata[RD0] = swim_roft(); break;
|
||||
rdata[RD0] = swim_woft( operand, miscdata ); break;
|
||||
case ROTF:
|
||||
rdata[RD_LEN] = HWORD_LEN;
|
||||
//this assignment actually undoes the byte swap
|
||||
//first index of data includes NAK/ACK just like write routines which only return ACK/NAK
|
||||
//second index of data includes actual byte read back
|
||||
*ret_hword = swim_roft( operand ); break;
|
||||
default:
|
||||
//opcode doesn't exist
|
||||
return ERR_UNKN_SWIM_OPCODE;
|
||||
|
|
@ -325,10 +329,84 @@ uint16_t append_pairity(uint8_t n)
|
|||
}
|
||||
}
|
||||
|
||||
/* Desc:read byte from SWIM
|
||||
* Pre: swim must be activated
|
||||
* Post:
|
||||
* Rtn: should return success/error and value read
|
||||
*/
|
||||
|
||||
//must match swim.s .equ statements!!!
|
||||
#define SWIM_RD_LS 0x01
|
||||
#define SWIM_WR_LS 0x02
|
||||
#define SWIM_RD_HS 0x11
|
||||
#define SWIM_WR_HS 0x12
|
||||
|
||||
uint16_t swim_roft(uint16_t addr)
|
||||
{
|
||||
//If >24Mhz SYSCLK, must add wait state to flash
|
||||
//can also enable prefetch buffer
|
||||
FLASH->ACR = FLASH_ACR_PRFTBE | 0x0001;
|
||||
//switch to 48Mhz
|
||||
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
|
||||
|
||||
uint16_t data_pb;
|
||||
uint32_t ack_data;
|
||||
uint32_t spddir_len;
|
||||
//bit sequence:
|
||||
//1bit header "0" Host comm
|
||||
//3bit command b2-1-0 "001" ROTF
|
||||
//1bit pairity xor of cmd "1"
|
||||
//1bit ACK "1" or NAK "0" from device
|
||||
// 0b0_0011
|
||||
data_pb = 0x3000;
|
||||
spddir_len = (SWIM_WR_LS<<16) | 4; //data + pairity ( '0' header not included)
|
||||
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
if (ack_data != ACK) goto end_swim;
|
||||
|
||||
//write N "number of bytes for ROTF"
|
||||
data_pb = 0x0180;
|
||||
spddir_len = (SWIM_WR_LS<<16) | 9;
|
||||
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
if (ack_data != ACK) goto end_swim;
|
||||
|
||||
//write @E extended address of write
|
||||
//always 0x00 since targetting stm8s003 which only has one section
|
||||
data_pb = 0x0000;
|
||||
spddir_len = (SWIM_WR_LS<<16) | 9;
|
||||
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
if (ack_data != ACK) goto end_swim;
|
||||
|
||||
//write @H high address of write
|
||||
data_pb = append_pairity( addr>>8 );
|
||||
spddir_len = (SWIM_WR_LS<<16) | 9;
|
||||
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
if (ack_data != ACK) goto end_swim;
|
||||
|
||||
//write @L high address of write
|
||||
data_pb = append_pairity( addr );
|
||||
//this is a read xfr because device will output data immediately after
|
||||
//writting last byte of command info
|
||||
spddir_len = (SWIM_RD_LS<<16) | 9;
|
||||
ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask);
|
||||
|
||||
//read DATA portion of write
|
||||
|
||||
//More bytes can be written
|
||||
//any time NAK is recieved must resend byte
|
||||
end_swim:
|
||||
|
||||
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE;
|
||||
//Don't need wait states or prefetch buffer anymore
|
||||
FLASH->ACR = 0x0000;
|
||||
return ack_data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Desc:write byte to SWIM
|
||||
* Pre: swim must be activated
|
||||
* Post:
|
||||
* Rtn: 0-NAK, 1-ACK beware, no response looks like ACK!
|
||||
* Rtn: 0-NAK, 1-ACK, 0xFF no response
|
||||
*/
|
||||
uint8_t swim_woft(uint16_t addr, uint8_t data)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
|
|||
void swim_activate();
|
||||
void swim_reset();
|
||||
uint8_t swim_out(uint16_t stream, uint8_t len);
|
||||
uint16_t swim_roft(uint16_t addr);
|
||||
uint8_t swim_woft(uint16_t addr, uint8_t data);
|
||||
uint16_t append_pairity(uint8_t n);
|
||||
|
||||
//assembly functions from swim.s
|
||||
extern uint32_t swim_xfr( uint16_t data_pb, uint32_t spddir_len, GPIO_TypeDef *swim_base, uint16_t swim_mask);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ void init_clock()
|
|||
//at startup HSI is selected SW = 00
|
||||
RCC->CFGR |= RCC_CFGR_SW_HSE;
|
||||
|
||||
//TODO poll RCC->CFGR SWS bits to ensure sysclk switched over
|
||||
|
||||
//Now the SYSCLK is running directly off the HSE 16Mhz xtal
|
||||
|
||||
/* (1) Test if PLL is used as System clock */
|
||||
|
|
|
|||
|
|
@ -405,8 +405,13 @@ local function swim( opcode, operand, misc, data )
|
|||
end
|
||||
|
||||
--process the return data string and return it to calling function
|
||||
RETURN_ACK_IDX = 3
|
||||
RETURN_DAT_IDX = 4
|
||||
if data_len then
|
||||
return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len)
|
||||
--return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len)
|
||||
error_code = data:byte(RETURN_ACK_IDX)
|
||||
data_len = data:byte(RETURN_DAT_IDX)
|
||||
return error_code, data_len
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -38,11 +38,26 @@ function main ()
|
|||
dict.io("SWIM_INIT", "SWIM_ON_EXP0")
|
||||
dict.swim("SWIM_ACTIVATE")
|
||||
|
||||
--holds SWIM pin low for 16usec+ to reset SWIM comms incase of error
|
||||
dict.swim("SWIM_RESET")
|
||||
|
||||
|
||||
--write 0A0h to SWIM_CSR
|
||||
--bit 5: allows entire memory range to be read & swim reset to be accessed
|
||||
--bit 7: masks internal reset sources (like WDT..?)
|
||||
print("wotf SWIM_CSR:", dict.swim("WOTF", 0x7F80, 0xA0))
|
||||
|
||||
--read SWIM_CSR
|
||||
print("rotf SWIM_CSR:", string.format("%X %X", dict.swim("ROTF", 0x7F80)))
|
||||
print("rotf SWIM_CSR:", string.format("%X %X", dict.swim("ROTF", 0x7F80)))
|
||||
print("rotf SWIM_CSR:", string.format("%X %X", dict.swim("ROTF", 0x7F80)))
|
||||
print("rotf SWIM_CSR:", string.format("%X %X", dict.swim("ROTF", 0x7F80)))
|
||||
print("rotf SWIM_CSR:", string.format("%X %X", dict.swim("ROTF", 0x7F80)))
|
||||
dict.swim("SWIM_RESET")
|
||||
|
||||
print("wotf SRST:", dict.swim("SWIM_SRST"))
|
||||
print("wotf SWIM_CSR:", dict.swim("WOTF", 0x7F80, 0xA0))
|
||||
|
||||
--now the SRST command is available, whole memory range available, and internal resets disabled
|
||||
--by default there is now a breakpoint set at reset vector
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
//SWIM commands
|
||||
#define SWIM_SRST 2 //reset device RL=3 (error, len, NAK/ACK)
|
||||
|
||||
#define ROTF 0x11 //read on the fly only one byte RL=3 (error, len, data)
|
||||
#define ROTF 0x11 //read on the fly only one byte RL=4 (usberror, len, swimerror, data)
|
||||
//#define ROTF_8B 0x18 //read on the fly RL=8
|
||||
//#define ROTF_128B 0x1F //read on the fly RL=128 (current max due to 254B limit)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue