diff --git a/firmware/source/io.c b/firmware/source/io.c index e2b0c49..9138d09 100644 --- a/firmware/source/io.c +++ b/firmware/source/io.c @@ -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<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; +} + diff --git a/firmware/source/swim.c.r3asreturn b/firmware/source/swim.c.r3asreturn new file mode 100644 index 0000000..54698cf --- /dev/null +++ b/firmware/source/swim.c.r3asreturn @@ -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; i11.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 ); + +} diff --git a/firmware/source/swim.c.rvreturn b/firmware/source/swim.c.rvreturn new file mode 100644 index 0000000..b5e3bd1 --- /dev/null +++ b/firmware/source/swim.c.rvreturn @@ -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; i11.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 ); + +} diff --git a/firmware/source/swim.h b/firmware/source/swim.h index 2c70734..ea996f3 100644 --- a/firmware/source/swim.h +++ b/firmware/source/swim.h @@ -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 diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index e0c84ce..1481f0c 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -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 diff --git a/shared/shared_dict_swim.h b/shared/shared_dict_swim.h index b268b98..844ff4f 100644 --- a/shared/shared_dict_swim.h +++ b/shared/shared_dict_swim.h @@ -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