Have SWIM write communications working on STM Adatper and INL6.

Able to enter active mode and Write on the fly.
Simple test to toggle LED on STM8 GPIO works!
Still quite far from ideal setup.  Some things needed:
-defines for ACK/NAK/NO_RESP in dictionary to report inteligbly to lua
-move test SWIM code into separate lua script
-define STM8-CIC registers for easier calling from lua
-entering active mode is too board dependent, need to use swim_base
-Need to make better use of device timers for entering active mode
-arm assembly is quite a mess, unaware of calling convention when writting
-stopping more than just r0-4, r5+ need to be restored if used
-thinking I'd like a full out assmebly file that gets compiled separately
-nothing is done to support SWIM with AVR
-hacking lack of powerful enough pullup on SWIM pin
	not much that can be done to get around this...
	don't want to add resistors to programmer for every pin I 'might' use
	don't want to add resistors to each board that's made
-seems to work well enough, but reads will prob prove challenging
-currently only running at slow speed with ton of NOPs
This commit is contained in:
Paul Molloy 2017-09-04 13:53:37 -05:00
parent 6eb0570335
commit f4bbad3d4a
7 changed files with 1164 additions and 10 deletions

View File

@ -179,8 +179,8 @@ void snes_init()
CSWR_HI();
//disable SRAM and put cart in PLAY mode
EXP0_OP();
EXP0_HI();
EXP0_OP();
//other control pins are inputs or unused, leave as IP pullup from reset
@ -221,6 +221,8 @@ uint8_t swim_init( uint8_t swim_lane )
EXP0_OP(); //enable as output to have above take effect
#endif
swim_pin = EXP0_;
swim_base = EXP0bank;
swim_mask = 1<<EXP0;
break;
case SWIM_ON_D0: //NES/FC carts with CICOprocesor
break;

View File

@ -28,8 +28,12 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
switch (opcode) {
case SWIM_ACTIVATE: swim_activate(); break;
case SWIM_RESET: swim_reset(); break;
// case SWIM_SRST: swim_srst(); break;
// case WOTF: swim_woft(operand); break;
case SWIM_SRST:
rdata[RD_LEN] = BYTE_LEN;
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;
@ -43,6 +47,8 @@ uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
}
uint8_t swim_pin;
uint16_t swim_mask;
GPIO_TypeDef *swim_base;
void delay( uint16_t delay )
{
@ -78,6 +84,8 @@ void swim_activate()
//toggle high->low T=1msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 720 = 500.9usec
//TODO move this timed code into a timer to make timing more stable
//between boards, pinport.c code, etc....
#ifdef STM_INL6
delay(719);
#endif
@ -120,12 +128,268 @@ void swim_activate()
*/
void swim_reset()
{
pinport_call( CTL_OP_, 0, swim_pin, 0);
//pinport_call( CTL_OP_, 0, swim_pin, 0);
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
//but looking at working programmers they do very long resets
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" )
#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" )
#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" )
//BSRR 0x18
#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base))
//BRR 0x28
#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base))
//OTYPER 0x04
#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define NO_RESP 0xFF
#define ACK 0x01
#define NAK 0x00
/* Desc:Transfer SWIM bit stream
* Always outputs '0' as first bit for header "from host"
* Will output len number of bits plus one for header
* Pre: swim_pin must be set and initialized via io.h
* stream has first data bit stored in bit15 - bit[15-len+2]
* pairity bit must be last bit in stream sequence bit[15-len+1]
* ie bit7 contains pairity bit for 8bit data stream
* Post:STM8 mcu SWIM active
* Rtn: 0xFF if no response, 0-NAK, 1-ACK.
*/
uint8_t swim_out(uint16_t stream, uint8_t len)//, GPIO_TypeDef *base)
{
//__asm("swim_out_begin:\n\t");
uint8_t return_val;
uint16_t pushpull = swim_base->OTYPER & ~swim_mask;
uint16_t opendrain = swim_base->OTYPER | swim_mask;
mov_swim_mask_r0(); //will store r0 to BSRR or BRR to set/clear
mov_pushpull_r6(); //will store r7 to OTYPER to drive high
mov_opendrain_r7(); //will store r6 to OTYPER to allow device to drive low
//store len in r5
__asm volatile ("mov r5, %[val]" : : [val] "r" (len) : "r5" );
//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
__asm volatile ("mov r4, %[val]" : : [val] "r" (stream) : "r4" );
__asm volatile ("lsl r4, #15" : : : "r4", "cc" );
//NOTE! cortex M0 only supports 'S' versions of lsl, sub, and, etc type
//opcodes. I get compiler error for including the 's' at end of instruction
//but lsl is same as lsls on M0, so just use lsl to avoid compiler error...
// bit start:
__asm("bit_start:\n\t");
//always start going low
str_r0_bres();
//current bit is stored in bit31 and Negative flag is set if
//current bit is '1'
__asm volatile ("bpl cur_bit_zero\n\t");
//go high since current bit is '1'
pp_swim();
str_r0_bset();
od_swim();
__asm volatile ("b det_next_bit\n\t");
__asm("cur_bit_zero:\n\t");
//must delay same amount of time as instructions above since branch
//add delay here until '1' and '0' are same length
NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP();
__asm("det_next_bit:\n\t");
//determine if this is the last bit
__asm volatile ("sub r5, #0x01" : : : "r5", "cc" );
//if last bit, go to stream end to prepare for ACK/NAK latch
__asm volatile ("bmi stream_end\n\t");
//determine next bit value
__asm volatile ("lsl r4, #1" : : : "r4", "cc" );
//Negative flag is now set for '1', and clear for '0'
//delay until 'go high' time for '0'
//add delay here to make all bit transfers longer
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//go to bit start
__asm volatile ("b bit_start\n\t");
//stream end:
__asm("stream_end:\n\t");
//delay until 'go high' time for '0'
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//delay until time to latch ACK/NAK from device
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
//8x NOP's misread at times...
//6x NOP's always misread, so must be too early
NOP(); //9x NOP's and we're getting stable reads
//first need to ensure device is actually responding
//sample when output should be low for a 1 or 0
//str_r0_bres(); //debug set low to denote when swim pin is being sampled with logic anaylzer
//sampling ~100nsec into bit transfer (low for 125nsec min)
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldrh r3, [%[mmio], #0x10]" : : [mmio] "r" (swim_base) : "r3");
__asm volatile ("and r3, r0" : : : "r3", "cc" );
//if it wasn't low, then the device didn't respond, so return error designating that
//__asm volatile ("bne no_response\n\t");
__asm ("mov %[rv], r3" : [rv] "=r" (return_val) );
if (return_val != 0) {
return NO_RESP;
}
//now delay until ~half way through bit transfer to sense 1-ACK or 0-NAK
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
//sampling 1.35usec into bit transfer (~half way)
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
//sampling 2.00usec into bit transfer oscope shows 2.7volts on stmad w/open drain
//debug set low to denote when swim pin is being sampled with logic anaylzer
//str_r0_bres();
//pp_swim();
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldr r3, [%[mmio], #0x10]" : : [mmio] "r" (swim_base) : "r3");
__asm volatile ("and r3, r0" : : : "r3", "cc" );
//move r3 to return val reg
__asm volatile ("mov %[rv], r3" : [rv] "=r" (return_val) );
//mask out swim pin so return value is 0 or non-zero based on device output
//return_val &= swim_mask;
if (return_val == 0x00) {
return NAK;
}
//made it to here then we got an ACK
return ACK;
}
/* Function to get parity of number n. It returns 0
* if n has odd parity, and returns 0xFF if n has even
* parity */
uint16_t append_pairity(uint8_t n)
{
//shift incoming data to upper byte
uint16_t data_pb = (n<<8);
uint8_t parity = 0;
while (n) {
parity = ~parity;
n = n & (n - 1);
}
if ( parity ) {
return (data_pb | 0x80);
} else {
return data_pb;
}
}
/* Desc:write byte to SWIM
* Pre: swim must be activated
* Post:
* Rtn: 0-NAK, 1-ACK beware, no response looks like ACK!
*/
uint8_t swim_woft(uint16_t addr, uint8_t data)
{
uint16_t data_pb;
uint8_t ack;
uint8_t len = 0;
//bit sequence:
//1bit header "0" Host comm
//3bit command b2-1-0 "010" WOTF
//1bit pairity xor of cmd "1"
//1bit ACK "1" or NAK "0" from device
// 0b0_0101
data_pb = 0x5000;
// data_pb = 0x4000; //test wrong pairity
len = 4; //data + pairity ( '0' header not included)
ack = swim_out( data_pb, len);
if (ack == NO_RESP) {
return NO_RESP;
} else if (ack == NAK) {
return NAK;
//wait and resend WOFT command
}
//write N "number of bytes for WOTF"
data_pb = 0x0180;
len = 9;
ack = swim_out( data_pb, len);
if (ack == NO_RESP) return NO_RESP;
//write @E extended address of write
//always 0x00 since targetting stm8s003 which only has one section
data_pb = 0x0000;
len = 9;
ack = swim_out( data_pb, len);
if (ack == NO_RESP) return NO_RESP;
//write @H high address of write
data_pb = append_pairity( addr>>8 );
len = 9;
ack = swim_out( data_pb, len);
if (ack == NO_RESP) return NO_RESP;
//write @L high address of write
data_pb = append_pairity( addr );
len = 9;
ack = swim_out( data_pb, len);
if (ack == NO_RESP) return NO_RESP;
//write DATA portion of write
data_pb = append_pairity( data );
len = 9;
ack = swim_out( data_pb, len);
//More bytes can be written
//any time NAK is recieved must resend byte
return ack;
}

View File

@ -0,0 +1,418 @@
#include "swim.h"
//=================================================================================================
//
// SWIM operations
// This file includes all the swim functions possible to be called from the swim dictionary.
//
// See description of the commands contained here in shared/shared_dictionaries.h
//
//=================================================================================================
/* Desc:Function takes an opcode which was transmitted via USB
* then decodes it to call designated function.
* shared_dict_swim.h is used in both host and fw to ensure opcodes/names align
* Pre: Macros must be defined in firmware pinport.h
* opcode must be defined in shared_dict_swim.h
* Post:function call complete.
* Rtn: SUCCESS if opcode found, error if opcode not present or other problem.
*/
uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata )
{
#define RD_LEN 0
#define RD0 1
#define RD1 2
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
case SWIM_ACTIVATE: swim_activate(); break;
case SWIM_RESET: swim_reset(); break;
// case SWIM_SRST: swim_srst(); break;
case WOTF:
rdata[RD_LEN] = BYTE_LEN;
rdata[RD0] = swim_woft(operand); break;
// case ROTF:
// rdata[RD_LEN] = BYTE_LEN;
// rdata[RD0] = swim_roft(); break;
default:
//opcode doesn't exist
return ERR_UNKN_SWIM_OPCODE;
}
return SUCCESS;
}
uint8_t swim_pin;
uint16_t swim_mask;
GPIO_TypeDef *swim_base;
void delay( uint16_t delay )
{
uint16_t i = 0;
for( i=0; i<delay; i++) {
NOP();
NOP();
} //16->11.8 on stmad
}
/* Desc:Initiate SWIM activate sequence
* Pre: swim_pin must be set and initialized via io.h
* Post:STM8 mcu SWIM active
* Rtn: SUCCESS if able to enter sucessfully.
*/
void swim_activate()
{
uint16_t i;
// pinport_call( CTL_OP_, 0, swim_pin, 0);
//toggles in this manner take 4.55-4.6usec on AVR
//toggles in this manner take 4.9-4.95usec on STM adapter
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
//toggle high->low T=1msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 720 = 500.9usec
//TODO move this timed code into a timer to make timing more stable
//between boards, pinport.c code, etc....
#ifdef STM_INL6
delay(719);
#endif
#ifdef STM_ADAPTER
delay(720);
#endif
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(718);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//toggle high->low T=0.5msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 358 = 256usec
delay(356);
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(355);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
//wait for device to take swim_pin low for ~16usec
//it's low for 128 SWIM clock sync pulse
//Best way to do this would be to wait for an interrupt
//on the swim pin going low, then have the isr count
//low time. If anything takes too long timeout.
//TODO
//return SUCCESS/FAIL depending on wether that ~16usec pulse was obtained
// return SUCCESS;
}
/* Desc:Hold swim pin low for >128 SWIM clocks (16usec)
* Pre: swim must be activated by
* Post:STM8 mcu SWIM comms are reset
* Rtn: SUCCESS if device responds with sync window.
*/
void swim_reset()
{
//pinport_call( CTL_OP_, 0, swim_pin, 0);
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" )
#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" )
#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" )
//BSRR 0x18
#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base))
//BRR 0x28
#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base))
//OTYPER 0x04
#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
/* Desc:Transfer SWIM bit stream
* Always outputs '0' as first bit for header "from host"
* Will output len number of bits plus one for header
* Pre: swim_pin must be set and initialized via io.h
* stream has first data bit stored in bit15 - bit[15-len+2]
* pairity bit must be last bit in stream sequence bit[15-len+1]
* ie bit7 contains pairity bit for 8bit data stream
* Post:STM8 mcu SWIM active
* Rtn: 0xFF if no response, 0-NAK, non-zero non-0xFF if ACK.
*/
uint16_t swim_out(uint16_t stream, uint8_t len)//, GPIO_TypeDef *base)
{
__asm("swim_out:\n\t");
uint16_t return_val;
uint16_t pushpull = swim_base->OTYPER & ~swim_mask;
uint16_t opendrain = swim_base->OTYPER | swim_mask;
mov_swim_mask_r0(); //will store r0 to BSRR or BRR to set/clear
mov_pushpull_r6(); //will store r7 to OTYPER to drive high
mov_opendrain_r7(); //will store r6 to OTYPER to allow device to drive low
//store len in r5
__asm volatile ("mov r5, %[val]" : : [val] "r" (len) : "r5" );
//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
__asm volatile ("lsl r4, %[val], #15" : : [val] "r" (stream) : "r4", "cc" );
//NOTE! cortex M0 only supports 'S' versions of lsl, sub, and, etc type
//opcodes. I get compiler error for including the 's' at end of instruction
//but lsl is same as lsls on M0, so just use lsl to avoid compiler error...
// bit start:
__asm("bit_start:\n\t");
//always start going low
str_r0_bres();
//current bit is stored in bit31 and Negative flag is set if
//current bit is '1'
__asm volatile ("bpl cur_bit_zero\n\t");
//go high since current bit is '1'
pp_swim();
str_r0_bset();
od_swim();
__asm volatile ("b det_next_bit\n\t");
__asm("cur_bit_zero:\n\t");
//must delay same amount of time as instructions above since branch
//add delay here until '1' and '0' are same length
NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP();
__asm("det_next_bit:\n\t");
//determine if this is the last bit
__asm volatile ("sub r5, #0x01" : : : "r5", "cc" );
//if last bit, go to stream end to prepare for ACK/NAK latch
__asm volatile ("bmi stream_end\n\t");
//determine next bit value
__asm volatile ("lsl r4, #1" : : : "r4", "cc" );
//Negative flag is now set for '1', and clear for '0'
//delay until 'go high' time for '0'
//add delay here to make all bit transfers longer
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//go to bit start
__asm volatile ("b bit_start\n\t");
//stream end:
__asm("stream_end:\n\t");
//delay until 'go high' time for '0'
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//delay until time to latch ACK/NAK from device
NOP(); NOP(); NOP(); NOP(); NOP();
//first need to ensure device is actually responding
//sample when output should be low for a 1 or 0
//str_r0_bres(); //debug set low to denote when swim pin is being sampled with logic anaylzer
//sampling ~100nsec into bit transfer (low for 125nsec min)
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldrh r3, [%[mmio], #0x10]" : : [mmio] "r" (swim_base) : "r3");
__asm volatile ("and r3, r0" : : : "r3" );
//if it wasn't low, then the device didn't respond, so return error designating that
__asm volatile ("bne no_response\n\t");
//if (return_val != 0) {
// goto no_response;
// }
//now delay until ~half way through bit transfer to sense 1-ACK or 0-NAK
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
//debug set low to denote when swim pin is being sampled with logic anaylzer
//str_r0_bres();
//sampling 1.35usec into bit transfer (~half way)
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldrh r3, [%[mmio], #0x10]" : : [mmio] "r" (swim_base) : "r3");
//move r3 to return val reg
__asm ("mov %[rv], r3" : [rv] "=r" (return_val) );
//mask out swim pin so return value is 0 or non-zero based on device output
return_val &= swim_mask;
if (return_val != 0xFF) {
//dummy check that keeps labels below available
//because inline assembly is pissing me off
goto return_response;
}
__asm("no_response:\n\t");
//return "fail to respond"
return_val = 0xFF;
return_response:
//return ACK/NAK from device
return return_val;
// __asm("bkpt");
//BSRR 0x18
//BRR 0x28
//OTYPER 0x04
// __asm ("mov r0, %[mask]" : : [mask] "r" (swim_mask) : "r0" );
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// //__asm volatile ("nop");
// //__asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x04]" : : [mmio] "r" (swim_base));
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("strh %[val], [%[mmio], #0x28]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x28]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//
// //for some reason this last store writes a different value to the mmio register! WTF!!!!
// //8000800: 851a strh r2, [r3, #40] ; 0x28^M
// //8000802: 831a strh r2, [r3, #24]^M
// //8000804: 851a strh r2, [r3, #40] ; 0x28^M
// //8000806: 831a strh r2, [r3, #24]^M
// //8000808: 851a strh r2, [r3, #40] ; 0x28^M
// //800080a: 831a strh r2, [r3, #24]^M
// //800080c: 851a strh r2, [r3, #40] ; 0x28^M
// //800080e: 831a strh r2, [r3, #24]^M
// //8000810: 8319 strh r1, [r3, #24]^M
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
// __asm volatile ("nop");
// __asm("bkpt");
// NOP();
// NOP();
// //delay(1);
// EXP0_HI();
// NOP();
// NOP();
// NOP();
// NOP();
// delay(10);
// EXP0_LO();
// NOP();
// NOP();
// NOP();
// NOP();
// NOP();
// EXP0_HI();
// asm (
// "TST LR, #0x40\n\t"
// "BEQ from_nonsecure\n\t"
// "from_secure:\n\t"
// "TST LR, #0x04\n\t"
// "ITE EQ\n\t"
// "MRSEQ R0, MSP\n\t"
// "MRSNE R0, PSP\n\t"
// "B hard_fault_handler_c\n\t"
// "from_nonsecure:\n\t"
// "MRS R0, CONTROL_NS\n\t"
// "TST R0, #2\n\t"
// "ITE EQ\n\t"
// "MRSEQ R0, MSP_NS\n\t"
// "MRSNE R0, PSP_NS\n\t"
// "B hard_fault_handler_c\n\t"
// );
//output bit stream from bit15 to bit15-len
}
/* Desc:write byte to SWIM
* Pre: swim must be activated
* Post:
* Rtn: 0-NAK, 1-ACK beware, no response looks like ACK!
*/
uint8_t swim_woft(uint8_t data)
{
//bit sequence:
//1bit header "0" Host comm
//3bit command b2-1-0 "010" WOTF
//1bit pairity xor of cmd "1"
//1bit ACK "1" or NAK "0" from device
// 0b0_0101
return swim_out( 0x5000, 4);
//1bit header "0" from host
//8bits data7:0
//1bit parity of data
//1bit ACK "1" or NAK "0" from device
// 0b0-data-pb
//swim_out( data<<8, 9);//, EXP0bank, EXP0 );
}

View File

@ -0,0 +1,428 @@
#include "swim.h"
//=================================================================================================
//
// SWIM operations
// This file includes all the swim functions possible to be called from the swim dictionary.
//
// See description of the commands contained here in shared/shared_dictionaries.h
//
//=================================================================================================
/* Desc:Function takes an opcode which was transmitted via USB
* then decodes it to call designated function.
* shared_dict_swim.h is used in both host and fw to ensure opcodes/names align
* Pre: Macros must be defined in firmware pinport.h
* opcode must be defined in shared_dict_swim.h
* Post:function call complete.
* Rtn: SUCCESS if opcode found, error if opcode not present or other problem.
*/
uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata )
{
#define RD_LEN 0
#define RD0 1
#define RD1 2
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
case SWIM_ACTIVATE: swim_activate(); break;
case SWIM_RESET: swim_reset(); break;
// case SWIM_SRST: swim_srst(); break;
case WOTF:
rdata[RD_LEN] = BYTE_LEN;
rdata[RD0] = swim_woft(operand); break;
// case ROTF:
// rdata[RD_LEN] = BYTE_LEN;
// rdata[RD0] = swim_roft(); break;
default:
//opcode doesn't exist
return ERR_UNKN_SWIM_OPCODE;
}
return SUCCESS;
}
uint8_t swim_pin;
uint16_t swim_mask;
GPIO_TypeDef *swim_base;
void delay( uint16_t delay )
{
uint16_t i = 0;
for( i=0; i<delay; i++) {
NOP();
NOP();
} //16->11.8 on stmad
}
/* Desc:Initiate SWIM activate sequence
* Pre: swim_pin must be set and initialized via io.h
* Post:STM8 mcu SWIM active
* Rtn: SUCCESS if able to enter sucessfully.
*/
void swim_activate()
{
uint16_t i;
// pinport_call( CTL_OP_, 0, swim_pin, 0);
//toggles in this manner take 4.55-4.6usec on AVR
//toggles in this manner take 4.9-4.95usec on STM adapter
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
//toggle high->low T=1msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 720 = 500.9usec
//TODO move this timed code into a timer to make timing more stable
//between boards, pinport.c code, etc....
#ifdef STM_INL6
delay(719);
#endif
#ifdef STM_ADAPTER
delay(720);
#endif
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(718);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//toggle high->low T=0.5msec 4x
for( i = 0; i < 4; i++) {
//STM adapter 358 = 256usec
delay(356);
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(355);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
//pinport_call( CTL_IP_PU_, 0, swim_pin, 0);
//wait for device to take swim_pin low for ~16usec
//it's low for 128 SWIM clock sync pulse
//Best way to do this would be to wait for an interrupt
//on the swim pin going low, then have the isr count
//low time. If anything takes too long timeout.
//TODO
//return SUCCESS/FAIL depending on wether that ~16usec pulse was obtained
// return SUCCESS;
}
/* Desc:Hold swim pin low for >128 SWIM clocks (16usec)
* Pre: swim must be activated by
* Post:STM8 mcu SWIM comms are reset
* Rtn: SUCCESS if device responds with sync window.
*/
void swim_reset()
{
//pinport_call( CTL_OP_, 0, swim_pin, 0);
//pulse low for 16usec spec says 16usec
//but looking at working programmers they do twice the delays below
pinport_call( CTL_SET_LO_, 0, swim_pin, 0);
delay(16);
pinport_call( CTL_SET_HI_, 0, swim_pin, 0);
}
#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" )
#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" )
#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" )
//BSRR 0x18
#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base))
//BRR 0x28
#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base))
//OTYPER 0x04
#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base))
/* Desc:Transfer SWIM bit stream
* Always outputs '0' as first bit for header "from host"
* Will output len number of bits plus one for header
* Pre: swim_pin must be set and initialized via io.h
* stream has first data bit stored in bit15 - bit[15-len+2]
* pairity bit must be last bit in stream sequence bit[15-len+1]
* ie bit7 contains pairity bit for 8bit data stream
* Post:STM8 mcu SWIM active
* Rtn: 0xFF if no response, 0-NAK, non-zero non-0xFF if ACK.
*/
uint8_t swim_out(uint16_t stream, uint8_t len)//, GPIO_TypeDef *base)
{
__asm("swim_out:\n\t");
uint8_t return_val;
uint16_t pushpull = swim_base->OTYPER & ~swim_mask;
uint16_t opendrain = swim_base->OTYPER | swim_mask;
mov_swim_mask_r0(); //will store r0 to BSRR or BRR to set/clear
mov_pushpull_r6(); //will store r7 to OTYPER to drive high
mov_opendrain_r7(); //will store r6 to OTYPER to allow device to drive low
//store len in r5
__asm volatile ("mov r5, %[val]" : : [val] "r" (len) : "r5" );
//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
__asm volatile ("lsl r4, %[val], #15" : : [val] "r" (stream) : "r4", "cc" );
//NOTE! cortex M0 only supports 'S' versions of lsl, sub, and, etc type
//opcodes. I get compiler error for including the 's' at end of instruction
//but lsl is same as lsls on M0, so just use lsl to avoid compiler error...
// bit start:
__asm("bit_start:\n\t");
//always start going low
str_r0_bres();
//current bit is stored in bit31 and Negative flag is set if
//current bit is '1'
__asm volatile ("bpl cur_bit_zero\n\t");
//go high since current bit is '1'
pp_swim();
str_r0_bset();
od_swim();
__asm volatile ("b det_next_bit\n\t");
__asm("cur_bit_zero:\n\t");
//must delay same amount of time as instructions above since branch
//add delay here until '1' and '0' are same length
NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP();
__asm("det_next_bit:\n\t");
//determine if this is the last bit
__asm volatile ("sub r5, #0x01" : : : "r5", "cc" );
//if last bit, go to stream end to prepare for ACK/NAK latch
__asm volatile ("bmi stream_end\n\t");
//determine next bit value
__asm volatile ("lsl r4, #1" : : : "r4", "cc" );
//Negative flag is now set for '1', and clear for '0'
//delay until 'go high' time for '0'
//add delay here to make all bit transfers longer
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//go to bit start
__asm volatile ("b bit_start\n\t");
//stream end:
__asm("stream_end:\n\t");
//delay until 'go high' time for '0'
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP();
//always go high for '0' (no effect if already high for '1')
pp_swim();
str_r0_bset();
od_swim();
//delay until time to latch ACK/NAK from device
NOP(); NOP(); NOP(); NOP(); NOP();
//first need to ensure device is actually responding
//sample when output should be low for a 1 or 0
//str_r0_bres(); //debug set low to denote when swim pin is being sampled with logic anaylzer
//sampling ~100nsec into bit transfer (low for 125nsec min)
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldrh %[rv], [%[mmio], #0x10]" : [rv] "=r" (return_val) : [mmio] "r" (swim_base));
__asm volatile ("and %[rv], r0" : [rv] "=r" (return_val) : : );
//if it wasn't low, then the device didn't respond, so return error designating that
__asm volatile ("bne no_response\n\t");
//if (return_val != 0) {
// goto no_response;
// }
//now delay until ~half way through bit transfer to sense 1-ACK or 0-NAK
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
//debug set low to denote when swim pin is being sampled with logic anaylzer
//str_r0_bres();
//sampling 1.35usec into bit transfer (~half way)
//latch SWIM pin value from IDR 0x10
__asm volatile ("ldrh %[rv], [%[mmio], #0x10]" : [rv] "=r" (return_val) : [mmio] "r" (swim_base));
//mask out swim pin so return value is 0 or non-zero based on device output
return_val &= swim_mask;
if (return_val != 0xFF) {
//dummy check that keeps labels below available
//because inline assembly is pissing me off
goto return_response;
}
__asm("no_response:\n\t");
//return "fail to respond"
return_val = 0xFF;
return_response:
//return ACK/NAK from device
return return_val;
// __asm("bkpt");
//BSRR 0x18
//BRR 0x28
//OTYPER 0x04
// __asm ("mov r0, %[mask]" : : [mask] "r" (swim_mask) : "r0" );
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("nop");
// __asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base));
// //__asm volatile ("nop");
// //__asm volatile ("nop");
// __asm volatile ("strh r0, [%[mmio], #0x04]" : : [mmio] "r" (swim_base));
// __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base));
// __asm volatile ("strh %[val], [%[mmio], #0x28]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x28]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//// __asm volatile ("nop");
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
//
// //for some reason this last store writes a different value to the mmio register! WTF!!!!
// //8000800: 851a strh r2, [r3, #40] ; 0x28^M
// //8000802: 831a strh r2, [r3, #24]^M
// //8000804: 851a strh r2, [r3, #40] ; 0x28^M
// //8000806: 831a strh r2, [r3, #24]^M
// //8000808: 851a strh r2, [r3, #40] ; 0x28^M
// //800080a: 831a strh r2, [r3, #24]^M
// //800080c: 851a strh r2, [r3, #40] ; 0x28^M
// //800080e: 831a strh r2, [r3, #24]^M
// //8000810: 8319 strh r1, [r3, #24]^M
// __asm volatile ("strh %[val], [%[mmio], #0x18]" : [val] "=l" (swim_mask) : [mmio] "l" (swim_base));
// __asm volatile ("nop");
// __asm("bkpt");
// NOP();
// NOP();
// //delay(1);
// EXP0_HI();
// NOP();
// NOP();
// NOP();
// NOP();
// delay(10);
// EXP0_LO();
// NOP();
// NOP();
// NOP();
// NOP();
// NOP();
// EXP0_HI();
// asm (
// "TST LR, #0x40\n\t"
// "BEQ from_nonsecure\n\t"
// "from_secure:\n\t"
// "TST LR, #0x04\n\t"
// "ITE EQ\n\t"
// "MRSEQ R0, MSP\n\t"
// "MRSNE R0, PSP\n\t"
// "B hard_fault_handler_c\n\t"
// "from_nonsecure:\n\t"
// "MRS R0, CONTROL_NS\n\t"
// "TST R0, #2\n\t"
// "ITE EQ\n\t"
// "MRSEQ R0, MSP_NS\n\t"
// "MRSNE R0, PSP_NS\n\t"
// "B hard_fault_handler_c\n\t"
// );
//output bit stream from bit15 to bit15-len
}
/* Desc:write byte to SWIM
* Pre: swim must be activated
* Post:
* Rtn: 0-NAK, 1-ACK beware, no response looks like ACK!
*/
uint8_t swim_woft(uint8_t data)
{
//bit sequence:
//1bit header "0" Host comm
//3bit command b2-1-0 "010" WOTF
//1bit pairity xor of cmd "1"
//1bit ACK "1" or NAK "0" from device
// 0b0_0101
uint16_t i;
i = swim_out( 0x5000, 4);
//trim return value to single byte
if (i == 0xFF) {
return 0xFF;
} else if ( i == 0) {
//NAK
return 0;
} else {
//ACK, continue to next byte
return 1;
}
//1bit header "0" from host
//8bits data7:0
//1bit parity of data
//1bit ACK "1" or NAK "0" from device
// 0b0-data-pb
//swim_out( data<<8, 9);//, EXP0bank, EXP0 );
}

View File

@ -6,9 +6,14 @@
#include "shared_errors.h"
extern uint8_t swim_pin;
extern GPIO_TypeDef *swim_base;
extern uint16_t swim_mask;
uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata );
void swim_activate();
void swim_reset();
uint8_t swim_out(uint16_t stream, uint8_t len);
uint8_t swim_woft(uint16_t addr, uint8_t data);
uint16_t append_pairity(uint8_t n);
#endif

View File

@ -41,8 +41,42 @@ function main ()
--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..?)
-- dict.swim("WOTF", 0xA0)
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
--reset the STM8 core
print("wotf SRST:", dict.swim("SWIM_SRST"))
--the STM8 core is now stalled @ reset vector
--can read/write to any address on STM8 core
--if CIC ROP bit is set, we can only r/w to periph & SRAM
--bit 2: SWIM is reset (exits active mode) when chip reset
--this forces successful SWIM entry on each execution of script
print("wotf SWIM_CSR:", dict.swim("WOTF", 0x7F80, 0xA4))
--test by blinking LED via periph register access
--v2 board has LED on hi_lo_sel PA2
print("wotf LED PA_CR1:", dict.swim("WOTF", 0x5003, 0xFF)) --default is input w/o pullup, now pullups enabled
--LED should be dimly lit
--set pin to pushpull
print("wotf LED PA_DDR:", dict.swim("WOTF", 0x5002, 0x04)) --PA2 is output CR1 set above makes pushpull
--LED is push/pull, ODR default to 0, so LED OFF
print("wotf LED PA_ODR:", dict.swim("WOTF", 0x5000, 0x04)) --PA2 output set LED ON!
print("wotf LED PA_ODR:", dict.swim("WOTF", 0x5000, 0x00)) --PA2 output set LED OFF!
--holds SWIM pin low for 16usec+ to reset SWIM comms incase of error
dict.swim("SWIM_RESET")
--reset the chip, if bit2 set in CSR the SWIM exits active mode with this reset
print("wotf SRST:", dict.swim("SWIM_SRST"))
--SWIM is now inactive chip is executing it's program code
--indicate to logic analyzer that test sequence above is complete
dict.pinport("CTL_SET_LO", "EXP0")
dict.io("IO_RESET")
-- debug = true

View File

@ -26,13 +26,16 @@
#define SWIM_RESET 1
//SWIM commands
#define SWIM_SRST 2 //reset device
#define SWIM_SRST 2 //reset device RL=3 (error, len, NAK/ACK)
#define ROTF 0x11 //read on the fly only one byte
#define ROTF 0x11 //read on the fly only one byte RL=3 (error, len, 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)
#define WOTF 0x21 //write on the fly only one byte
//write on the fly only one byte
//operand = address (extended addr always 0)
//miscdata = data to write @ address
#define WOTF 0x21 //RL=3 (error code, data len, 0-NAK 1-ACK)
//#define WOTF_8B 0x28 //write 8Bytes on the fly
//#define WOTF_128B 0x2F //write 128Bytes on the fly