/* Symbol Table */ // ISR = LABEL: 257 // ISR_preserve_s0 = CONSTANT: 13 // ISR_preserve_s1 = CONSTANT: 14 // ISR_preserve_s2 = CONSTANT: 15 // LED0 = CONSTANT: 1 // LED0_sequence = CONSTANT: 16 // LED1 = CONSTANT: 2 // LED1_sequence = CONSTANT: 17 // LED2 = CONSTANT: 4 // LED2_sequence = CONSTANT: 18 // LED3 = CONSTANT: 8 // LED3_sequence = CONSTANT: 19 // LED4 = CONSTANT: 16 // LED4_sequence = CONSTANT: 20 // LED5 = CONSTANT: 32 // LED5_sequence = CONSTANT: 21 // LED6 = CONSTANT: 64 // LED6_sequence = CONSTANT: 22 // LED7 = CONSTANT: 128 // LED7_sequence = CONSTANT: 23 // LED_port = CONSTANT: 128 // LED_to_duty = LABEL: 167 // PWM_channel0 = CONSTANT: 1 // PWM_channel1 = CONSTANT: 2 // PWM_channel10 = CONSTANT: 11 // PWM_channel11 = CONSTANT: 12 // PWM_channel2 = CONSTANT: 3 // PWM_channel3 = CONSTANT: 4 // PWM_channel4 = CONSTANT: 5 // PWM_channel5 = CONSTANT: 6 // PWM_channel6 = CONSTANT: 7 // PWM_channel7 = CONSTANT: 8 // PWM_channel8 = CONSTANT: 9 // PWM_channel9 = CONSTANT: 10 // PWM_duty_counter = CONSTANT: 0 // UART_data = REGISTER: 15 // UART_read_port = CONSTANT: 1 // UART_write = LABEL: 191 // UART_write_port = CONSTANT: 32 // character_0 = CONSTANT: 48 // character_1 = CONSTANT: 49 // character_2 = CONSTANT: 50 // character_3 = CONSTANT: 51 // character_4 = CONSTANT: 52 // character_5 = CONSTANT: 53 // character_6 = CONSTANT: 54 // character_7 = CONSTANT: 55 // character_8 = CONSTANT: 56 // character_9 = CONSTANT: 57 // character_A = CONSTANT: 65 // character_B = CONSTANT: 66 // character_BS = CONSTANT: 8 // character_C = CONSTANT: 67 // character_CR = CONSTANT: 13 // character_D = CONSTANT: 68 // character_E = CONSTANT: 69 // character_F = CONSTANT: 70 // character_G = CONSTANT: 71 // character_H = CONSTANT: 72 // character_I = CONSTANT: 73 // character_J = CONSTANT: 74 // character_K = CONSTANT: 75 // character_L = CONSTANT: 76 // character_M = CONSTANT: 77 // character_N = CONSTANT: 78 // character_O = CONSTANT: 79 // character_P = CONSTANT: 80 // character_Q = CONSTANT: 81 // character_R = CONSTANT: 82 // character_S = CONSTANT: 83 // character_T = CONSTANT: 84 // character_U = CONSTANT: 85 // character_V = CONSTANT: 86 // character_W = CONSTANT: 87 // character_X = CONSTANT: 88 // character_Y = CONSTANT: 89 // character_Z = CONSTANT: 90 // character_a = CONSTANT: 97 // character_b = CONSTANT: 98 // character_c = CONSTANT: 99 // character_colon = CONSTANT: 58 // character_comma = CONSTANT: 44 // character_d = CONSTANT: 100 // character_divide = CONSTANT: 47 // character_dollar = CONSTANT: 36 // character_e = CONSTANT: 101 // character_equals = CONSTANT: 61 // character_exclaim = CONSTANT: 33 // character_f = CONSTANT: 102 // character_g = CONSTANT: 103 // character_greater_than = CONSTANT: 62 // character_h = CONSTANT: 104 // character_i = CONSTANT: 105 // character_j = CONSTANT: 106 // character_k = CONSTANT: 107 // character_l = CONSTANT: 108 // character_less_than = CONSTANT: 60 // character_m = CONSTANT: 109 // character_minus = CONSTANT: 45 // character_n = CONSTANT: 110 // character_o = CONSTANT: 111 // character_p = CONSTANT: 112 // character_plus = CONSTANT: 43 // character_q = CONSTANT: 113 // character_question = CONSTANT: 63 // character_r = CONSTANT: 114 // character_s = CONSTANT: 115 // character_semi_colon = CONSTANT: 59 // character_space = CONSTANT: 32 // character_stop = CONSTANT: 46 // character_t = CONSTANT: 116 // character_u = CONSTANT: 117 // character_v = CONSTANT: 118 // character_w = CONSTANT: 119 // character_x = CONSTANT: 120 // character_y = CONSTANT: 121 // character_z = CONSTANT: 122 // clear_loop = LABEL: 2 // cold_start = LABEL: 0 // delay_s0_loop = LABEL: 23 // delay_s1_loop = LABEL: 22 // delay_s2_loop = LABEL: 21 // enable_int = LABEL: 7 // go_down = LABEL: 176 // go_down_loop = LABEL: 177 // go_up_loop = LABEL: 171 // inc_LED0 = LABEL: 35 // inc_LED1 = LABEL: 54 // inc_LED2 = LABEL: 71 // inc_LED3 = LABEL: 88 // inc_LED4 = LABEL: 105 // inc_LED5 = LABEL: 122 // inc_LED6 = LABEL: 144 // inc_LED7 = LABEL: 158 // normal_LED1 = LABEL: 48 // normal_LED6 = LABEL: 138 // read_character = LABEL: 185 // read_from_UART = LABEL: 181 // rx_data_present = CONSTANT: 4 // rx_full = CONSTANT: 16 // rx_half_full = CONSTANT: 8 // s0 = REGISTER: 0 // s1 = REGISTER: 1 // s2 = REGISTER: 2 // s3 = REGISTER: 3 // s4 = REGISTER: 4 // s5 = REGISTER: 5 // s6 = REGISTER: 6 // s7 = REGISTER: 7 // s8 = REGISTER: 8 // s9 = REGISTER: 9 // sA = REGISTER: 10 // sB = REGISTER: 11 // sC = REGISTER: 12 // sD = REGISTER: 13 // sE = REGISTER: 14 // sF = REGISTER: 15 // send_CR = LABEL: 193 // send_OK = LABEL: 251 // send_space = LABEL: 196 // send_to_UART = LABEL: 187 // send_welcome = LABEL: 199 // simple_IO10 = CONSTANT: 2 // simple_IO11 = CONSTANT: 4 // simple_IO12 = CONSTANT: 8 // simple_IO9 = CONSTANT: 1 // simple_port = CONSTANT: 64 // spare1 = CONSTANT: 32 // spare2 = CONSTANT: 64 // spare3 = CONSTANT: 128 // status_port = CONSTANT: 0 // test_LED0_start = LABEL: 37 // test_LED1_start = LABEL: 56 // test_LED2_start = LABEL: 73 // test_LED3_start = LABEL: 90 // test_LED4_start = LABEL: 107 // test_LED5_start = LABEL: 124 // test_LED6_start = LABEL: 146 // test_LED7_start = LABEL: 160 // tx_full = CONSTANT: 2 // tx_half_full = CONSTANT: 1 // update_LED0 = LABEL: 40 // update_LED1 = LABEL: 62 // update_LED2 = LABEL: 79 // update_LED3 = LABEL: 96 // update_LED4 = LABEL: 113 // update_LED5 = LABEL: 130 // update_LED6 = LABEL: 149 // update_LED7 = LABEL: 163 // warm_start = LABEL: 20 /* Program Code */ // #1: ; KCPSM3 Program - Automatic Pulse Width Modulation (PWM) Control on the Spartan-3E Starter Kit. // #2: ; // #3: ; Ken Chapman - Xilinx Ltd // #4: ; // #5: ; Version v1.00 - 24th May 2006 // #6: ; // #7: ; Automatically sequences the LEDs on the board using PWM to change intensity. // #8: ; // #9: ;************************************************************************************** // #10: ; Port definitions // #11: ;************************************************************************************** // #12: ; // #13: ; // #14: ; // #15: CONSTANT(LED_port,128) ;8 simple LEDs // #16: CONSTANT(LED0,1) ; LED 0 - bit0 // #17: CONSTANT(LED1,2) ; 1 - bit1 // #18: CONSTANT(LED2,4) ; 2 - bit2 // #19: CONSTANT(LED3,8) ; 3 - bit3 // #20: CONSTANT(LED4,16) ; 4 - bit4 // #21: CONSTANT(LED5,32) ; 5 - bit5 // #22: CONSTANT(LED6,64) ; 6 - bit6 // #23: CONSTANT(LED7,128) ; 7 - bit7 // #24: ; // #25: ; // #26: CONSTANT(simple_port,64) ;4 simple outputs // #27: CONSTANT(simple_IO9,1) ; Header IO9 - bit0 // #28: CONSTANT(simple_IO10,2) ; IO10 - bit1 // #29: CONSTANT(simple_IO11,4) ; IO11 - bit2 // #30: CONSTANT(simple_IO12,8) ; IO12 - bit3 // #31: ; // #32: ; // #33: ; // #34: CONSTANT(status_port,0) ;UART status input // #35: CONSTANT(tx_half_full,1) ; Transmitter half full - bit0 // #36: CONSTANT(tx_full,2) ; FIFO full - bit1 // #37: CONSTANT(rx_data_present,4) ; Receiver data present - bit2 // #38: CONSTANT(rx_half_full,8) ; FIFO half full - bit3 // #39: CONSTANT(rx_full,16) ; full - bit4 // #40: CONSTANT(spare1,32) ; spare '0' - bit5 // #41: CONSTANT(spare2,64) ; spare '0' - bit6 // #42: CONSTANT(spare3,128) ; spare '0' - bit7 // #43: ; // #44: CONSTANT(UART_read_port,1) ;UART Rx data input // #45: ; // #46: CONSTANT(UART_write_port,32) ;UART Tx data output // #47: ; // #48: ; // #49: ; // #50: ;************************************************************************************** // #51: ; Special Register usage // #52: ;************************************************************************************** // #53: ; // #54: NAMEREG(sF,UART_data) ;used to pass data to and from the UART // #55: ; // #56: ; // #57: ; // #58: ;************************************************************************************** // #59: ;Scratch Pad Memory Locations // #60: ;************************************************************************************** // #61: ; // #62: CONSTANT(PWM_duty_counter,0) ;Duty Counter 0 to 255 within 1KHz period (1ms) // #63: CONSTANT(PWM_channel0,1) ;PWM settings for each channel // #64: CONSTANT(PWM_channel1,2) ; Channels 0 to 7 = LEDs 0 to 7 // #65: CONSTANT(PWM_channel2,3) ; Channels 8 to 11 = IO9 to IO12 // #66: CONSTANT(PWM_channel3,4) // #67: CONSTANT(PWM_channel4,5) // #68: CONSTANT(PWM_channel5,6) // #69: CONSTANT(PWM_channel6,7) // #70: CONSTANT(PWM_channel7,8) // #71: CONSTANT(PWM_channel8,9) // #72: CONSTANT(PWM_channel9,10) // #73: CONSTANT(PWM_channel10,11) // #74: CONSTANT(PWM_channel11,12) // #75: CONSTANT(ISR_preserve_s0,13) ;preserve register contents during Interrupt Service Routine // #76: CONSTANT(ISR_preserve_s1,14) // #77: CONSTANT(ISR_preserve_s2,15) // #78: ; // #79: ; // #80: CONSTANT(LED0_sequence,16) ;LED sequence values // #81: CONSTANT(LED1_sequence,17) // #82: CONSTANT(LED2_sequence,18) // #83: CONSTANT(LED3_sequence,19) // #84: CONSTANT(LED4_sequence,20) // #85: CONSTANT(LED5_sequence,21) // #86: CONSTANT(LED6_sequence,22) // #87: CONSTANT(LED7_sequence,23) // #88: ; // #89: ; // #90: ; // #91: ;************************************************************************************** // #92: ;Useful data constants // #93: ;************************************************************************************** // #94: ; // #95: ; // #96: ; // #97: ; // #98: ;ASCII table // #99: ; // #100: CONSTANT(character_a,97) // #101: CONSTANT(character_b,98) // #102: CONSTANT(character_c,99) // #103: CONSTANT(character_d,100) // #104: CONSTANT(character_e,101) // #105: CONSTANT(character_f,102) // #106: CONSTANT(character_g,103) // #107: CONSTANT(character_h,104) // #108: CONSTANT(character_i,105) // #109: CONSTANT(character_j,106) // #110: CONSTANT(character_k,107) // #111: CONSTANT(character_l,108) // #112: CONSTANT(character_m,109) // #113: CONSTANT(character_n,110) // #114: CONSTANT(character_o,111) // #115: CONSTANT(character_p,112) // #116: CONSTANT(character_q,113) // #117: CONSTANT(character_r,114) // #118: CONSTANT(character_s,115) // #119: CONSTANT(character_t,116) // #120: CONSTANT(character_u,117) // #121: CONSTANT(character_v,118) // #122: CONSTANT(character_w,119) // #123: CONSTANT(character_x,120) // #124: CONSTANT(character_y,121) // #125: CONSTANT(character_z,122) // #126: CONSTANT(character_A,65) // #127: CONSTANT(character_B,66) // #128: CONSTANT(character_C,67) // #129: CONSTANT(character_D,68) // #130: CONSTANT(character_E,69) // #131: CONSTANT(character_F,70) // #132: CONSTANT(character_G,71) // #133: CONSTANT(character_H,72) // #134: CONSTANT(character_I,73) // #135: CONSTANT(character_J,74) // #136: CONSTANT(character_K,75) // #137: CONSTANT(character_L,76) // #138: CONSTANT(character_M,77) // #139: CONSTANT(character_N,78) // #140: CONSTANT(character_O,79) // #141: CONSTANT(character_P,80) // #142: CONSTANT(character_Q,81) // #143: CONSTANT(character_R,82) // #144: CONSTANT(character_S,83) // #145: CONSTANT(character_T,84) // #146: CONSTANT(character_U,85) // #147: CONSTANT(character_V,86) // #148: CONSTANT(character_W,87) // #149: CONSTANT(character_X,88) // #150: CONSTANT(character_Y,89) // #151: CONSTANT(character_Z,90) // #152: CONSTANT(character_0,48) // #153: CONSTANT(character_1,49) // #154: CONSTANT(character_2,50) // #155: CONSTANT(character_3,51) // #156: CONSTANT(character_4,52) // #157: CONSTANT(character_5,53) // #158: CONSTANT(character_6,54) // #159: CONSTANT(character_7,55) // #160: CONSTANT(character_8,56) // #161: CONSTANT(character_9,57) // #162: CONSTANT(character_colon,58) // #163: CONSTANT(character_stop,46) // #164: CONSTANT(character_semi_colon,59) // #165: CONSTANT(character_minus,45) // #166: CONSTANT(character_divide,47) ;'/' // #167: CONSTANT(character_plus,43) // #168: CONSTANT(character_comma,44) // #169: CONSTANT(character_less_than,60) // #170: CONSTANT(character_greater_than,62) // #171: CONSTANT(character_equals,61) // #172: CONSTANT(character_space,32) // #173: CONSTANT(character_CR,13) ;carriage return // #174: CONSTANT(character_question,63) ;'?' // #175: CONSTANT(character_dollar,36) // #176: CONSTANT(character_exclaim,33) ;'!' // #177: CONSTANT(character_BS,8) ;Back Space command character // #178: ; // #179: ; // #180: ; // #181: ; // #182: ; // #183: ;************************************************************************************** // #184: ;Initialise the system // #185: ;************************************************************************************** // #186: ; // #187: ; All PWM channels initialise to off (zero). // #188: ; Simple I/O outputs will remain off at all times. // #189: ; // @000 #190: [cold_start] 00000 // @000 #190: LOAD(s0,0) 00101 // @001 #191: LOAD(s1,PWM_channel0) // @002 #192: [clear_loop] 2f010 // @002 #192: STORE(s0,s1) 1410c // @003 #193: COMPARE(s1,PWM_channel11) 35007 // @004 #194: JUMP(Z,enable_int) 18101 // @005 #195: ADD(s1,1) 34002 // @006 #196: JUMP(clear_loop) // #197: ; // @007 #198: [enable_int] 3c001 // @007 #198: ENABLE(INTERRUPT) ;interrupts used to drive servo // #199: ; 300c7 // @008 #200: CALL(send_welcome) ;Write welcome message to UART 300fb // @009 #201: CALL(send_OK) // #202: ; // #203: ; // #204: ; Initialise LED pattern sequence // #205: ; 00001 // @00a #206: LOAD(s0,1) ;trigger to start wave pattern 2e010 // @00b #207: STORE(s0,LED0_sequence) 00000 // @00c #208: LOAD(s0,0) 2e011 // @00d #209: STORE(s0,LED1_sequence) 2e012 // @00e #210: STORE(s0,LED2_sequence) 2e013 // @00f #211: STORE(s0,LED3_sequence) 2e014 // @010 #212: STORE(s0,LED4_sequence) 2e015 // @011 #213: STORE(s0,LED5_sequence) 2e016 // @012 #214: STORE(s0,LED6_sequence) 2e017 // @013 #215: STORE(s0,LED7_sequence) // #216: ; // #217: ;************************************************************************************** // #218: ; Main program // #219: ;************************************************************************************** // #220: ; // #221: ; Provides a pattern of interest on the LEDs :-) // #222: ; // #223: ; Each LED increases intensity in 8 steps and then decreases intensity in 8 steps until it is off. // #224: ; The middle LEDs (LD2 to LD5) each start to turn on when either neighbour is turned half on and increasing // #225: ; to provide the effect of a passing a 'wave' of light passing from side to side. The pair of LEDs at each // #226: ; (LD0, Ld1 and LD6, LD7) are required to reflect the 'wave' so that the pattern continues. // #227: ; // #228: ; I'm sure this code cold be written in more elegant way, but I leave that as an exercise to you :-) // #229: ; // @014 #230: [warm_start] 00203 // @014 #230: LOAD(s2,3) ;simple delay loop (time will be increased by ISR processing) // @015 #231: [delay_s2_loop] 001ff // @015 #231: LOAD(s1,FF) // @016 #232: [delay_s1_loop] 000ff // @016 #232: LOAD(s0,FF) // @017 #233: [delay_s0_loop] 1c001 // @017 #233: SUB(s0,1) 35c17 // @018 #234: JUMP(NC,delay_s0_loop) 1c101 // @019 #235: SUB(s1,1) 35c16 // @01a #236: JUMP(NC,delay_s1_loop) 1c201 // @01b #237: SUB(s2,1) 35c15 // @01c #238: JUMP(NC,delay_s2_loop) // #239: ; // #240: ;Pattern generation // #241: ; 06010 // @01d #242: FETCH(s0,LED0_sequence) ;read sequence for LED0 14000 // @01e #243: COMPARE(s0,0) 35025 // @01f #244: JUMP(Z,test_LED0_start) 1c020 // @020 #245: SUB(s0,32) ;Count longer to ensure end stops then reset count if maximum 35028 // @021 #246: JUMP(Z,update_LED0) 18020 // @022 #247: ADD(s0,32) // @023 #248: [inc_LED0] 18001 // @023 #248: ADD(s0,1) ;increment counter 34028 // @024 #249: JUMP(update_LED0) // @025 #250: [test_LED0_start] 06111 // @025 #250: FETCH(s1,LED1_sequence) ;start LED0 if LED1 = 4 14104 // @026 #251: COMPARE(s1,4) 35023 // @027 #252: JUMP(Z,inc_LED0) // @028 #253: [update_LED0] 2e010 // @028 #253: STORE(s0,LED0_sequence) 300a7 // @029 #254: CALL(LED_to_duty) 2e101 // @02a #255: STORE(s1,PWM_channel0) // #256: ; 06110 // @02b #257: FETCH(s1,LED0_sequence) ; refresh LED1 if LED0 = 11 (0B hex) to reflect wave 1410b // @02c #258: COMPARE(s1,11) 35430 // @02d #259: JUMP(NZ,normal_LED1) 00004 // @02e #260: LOAD(s0,4) 3403e // @02f #261: JUMP(update_LED1) // @030 #262: [normal_LED1] 06011 // @030 #262: FETCH(s0,LED1_sequence) ;read sequence for LED1 14000 // @031 #263: COMPARE(s0,0) 35038 // @032 #264: JUMP(Z,test_LED1_start) 1c010 // @033 #265: SUB(s0,16) ;reset count if maximum 3503e // @034 #266: JUMP(Z,update_LED1) 18010 // @035 #267: ADD(s0,16) // @036 #268: [inc_LED1] 18001 // @036 #268: ADD(s0,1) ;increment counter 3403e // @037 #269: JUMP(update_LED1) // @038 #270: [test_LED1_start] 06110 // @038 #270: FETCH(s1,LED0_sequence) ;start LED1 if LED0 = 11 (0B hex) to reflect wave 1410b // @039 #271: COMPARE(s1,11) 35036 // @03a #272: JUMP(Z,inc_LED1) 06112 // @03b #273: FETCH(s1,LED2_sequence) ;start LED1 if LED2 = 4 14104 // @03c #274: COMPARE(s1,4) 35036 // @03d #275: JUMP(Z,inc_LED1) // @03e #276: [update_LED1] 2e011 // @03e #276: STORE(s0,LED1_sequence) 300a7 // @03f #277: CALL(LED_to_duty) 2e102 // @040 #278: STORE(s1,PWM_channel1) // #279: ; 06012 // @041 #280: FETCH(s0,LED2_sequence) ;read sequence for LED2 14000 // @042 #281: COMPARE(s0,0) 35049 // @043 #282: JUMP(Z,test_LED2_start) 1c010 // @044 #283: SUB(s0,16) ;reset count if maximum 3504f // @045 #284: JUMP(Z,update_LED2) 18010 // @046 #285: ADD(s0,16) // @047 #286: [inc_LED2] 18001 // @047 #286: ADD(s0,1) ;increment counter 3404f // @048 #287: JUMP(update_LED2) // @049 #288: [test_LED2_start] 06111 // @049 #288: FETCH(s1,LED1_sequence) ;start LED2 if LED1 = 4 14104 // @04a #289: COMPARE(s1,4) 35047 // @04b #290: JUMP(Z,inc_LED2) 06113 // @04c #291: FETCH(s1,LED3_sequence) ;start LED2 if LED3 = 4 14104 // @04d #292: COMPARE(s1,4) 35047 // @04e #293: JUMP(Z,inc_LED2) // @04f #294: [update_LED2] 2e012 // @04f #294: STORE(s0,LED2_sequence) 300a7 // @050 #295: CALL(LED_to_duty) 2e103 // @051 #296: STORE(s1,PWM_channel2) // #297: ; // #298: ; 06013 // @052 #299: FETCH(s0,LED3_sequence) ;read sequence for LED3 14000 // @053 #300: COMPARE(s0,0) 3505a // @054 #301: JUMP(Z,test_LED3_start) 1c010 // @055 #302: SUB(s0,16) ;reset count if maximum 35060 // @056 #303: JUMP(Z,update_LED3) 18010 // @057 #304: ADD(s0,16) // @058 #305: [inc_LED3] 18001 // @058 #305: ADD(s0,1) ;increment counter 34060 // @059 #306: JUMP(update_LED3) // @05a #307: [test_LED3_start] 06112 // @05a #307: FETCH(s1,LED2_sequence) ;start LED3 if LED2 = 4 14104 // @05b #308: COMPARE(s1,4) 35058 // @05c #309: JUMP(Z,inc_LED3) 06114 // @05d #310: FETCH(s1,LED4_sequence) ;start LED3 if LED4 = 4 14104 // @05e #311: COMPARE(s1,4) 35058 // @05f #312: JUMP(Z,inc_LED3) // @060 #313: [update_LED3] 2e013 // @060 #313: STORE(s0,LED3_sequence) 300a7 // @061 #314: CALL(LED_to_duty) 2e104 // @062 #315: STORE(s1,PWM_channel3) // #316: ; 06014 // @063 #317: FETCH(s0,LED4_sequence) ;read sequence for LED4 14000 // @064 #318: COMPARE(s0,0) 3506b // @065 #319: JUMP(Z,test_LED4_start) 1c010 // @066 #320: SUB(s0,16) ;reset count if maximum 35071 // @067 #321: JUMP(Z,update_LED4) 18010 // @068 #322: ADD(s0,16) // @069 #323: [inc_LED4] 18001 // @069 #323: ADD(s0,1) ;increment counter 34071 // @06a #324: JUMP(update_LED4) // @06b #325: [test_LED4_start] 06113 // @06b #325: FETCH(s1,LED3_sequence) ;start LED4 if LED3 = 4 14104 // @06c #326: COMPARE(s1,4) 35069 // @06d #327: JUMP(Z,inc_LED4) 06115 // @06e #328: FETCH(s1,LED5_sequence) ;start LED4 if LED5 = 4 14104 // @06f #329: COMPARE(s1,4) 35069 // @070 #330: JUMP(Z,inc_LED4) // @071 #331: [update_LED4] 2e014 // @071 #331: STORE(s0,LED4_sequence) 300a7 // @072 #332: CALL(LED_to_duty) 2e105 // @073 #333: STORE(s1,PWM_channel4) // #334: ; 06015 // @074 #335: FETCH(s0,LED5_sequence) ;read sequence for LED5 14000 // @075 #336: COMPARE(s0,0) 3507c // @076 #337: JUMP(Z,test_LED5_start) 1c010 // @077 #338: SUB(s0,16) ;reset count if maximum 35082 // @078 #339: JUMP(Z,update_LED5) 18010 // @079 #340: ADD(s0,16) // @07a #341: [inc_LED5] 18001 // @07a #341: ADD(s0,1) ;increment counter 34082 // @07b #342: JUMP(update_LED5) // @07c #343: [test_LED5_start] 06114 // @07c #343: FETCH(s1,LED4_sequence) ;start LED5 if LED4 = 4 14104 // @07d #344: COMPARE(s1,4) 3507a // @07e #345: JUMP(Z,inc_LED5) 06116 // @07f #346: FETCH(s1,LED6_sequence) ;start LED5 if LED6 = 4 14104 // @080 #347: COMPARE(s1,4) 3507a // @081 #348: JUMP(Z,inc_LED5) // @082 #349: [update_LED5] 2e015 // @082 #349: STORE(s0,LED5_sequence) 300a7 // @083 #350: CALL(LED_to_duty) 2e106 // @084 #351: STORE(s1,PWM_channel5) // #352: ; 06117 // @085 #353: FETCH(s1,LED7_sequence) ; refresh LED6 if LED7 = 11 (0B hex) to reflect wave 1410b // @086 #354: COMPARE(s1,11) 3548a // @087 #355: JUMP(NZ,normal_LED6) 00004 // @088 #356: LOAD(s0,4) 34095 // @089 #357: JUMP(update_LED6) // @08a #358: [normal_LED6] 06016 // @08a #358: FETCH(s0,LED6_sequence) ;read sequence for LED6 14000 // @08b #359: COMPARE(s0,0) 35092 // @08c #360: JUMP(Z,test_LED6_start) 1c010 // @08d #361: SUB(s0,16) ;reset count if maximum 35095 // @08e #362: JUMP(Z,update_LED6) 18010 // @08f #363: ADD(s0,16) // @090 #364: [inc_LED6] 18001 // @090 #364: ADD(s0,1) ;increment counter 34095 // @091 #365: JUMP(update_LED6) // @092 #366: [test_LED6_start] 06115 // @092 #366: FETCH(s1,LED5_sequence) ;start LED6 if LED5 = 4 14104 // @093 #367: COMPARE(s1,4) 35090 // @094 #368: JUMP(Z,inc_LED6) // @095 #369: [update_LED6] 2e016 // @095 #369: STORE(s0,LED6_sequence) 300a7 // @096 #370: CALL(LED_to_duty) 2e107 // @097 #371: STORE(s1,PWM_channel6) // #372: ; 06017 // @098 #373: FETCH(s0,LED7_sequence) ;read sequence for LED7 14000 // @099 #374: COMPARE(s0,0) 350a0 // @09a #375: JUMP(Z,test_LED7_start) 1c020 // @09b #376: SUB(s0,32) ;Count longer to ensure end stops then reset count if maximum 350a3 // @09c #377: JUMP(Z,update_LED7) 18020 // @09d #378: ADD(s0,32) // @09e #379: [inc_LED7] 18001 // @09e #379: ADD(s0,1) ;increment counter 340a3 // @09f #380: JUMP(update_LED7) // @0a0 #381: [test_LED7_start] 06116 // @0a0 #381: FETCH(s1,LED6_sequence) ;start LED7 if LED6 = 4 14104 // @0a1 #382: COMPARE(s1,4) 3509e // @0a2 #383: JUMP(Z,inc_LED7) // @0a3 #384: [update_LED7] 2e017 // @0a3 #384: STORE(s0,LED7_sequence) 300a7 // @0a4 #385: CALL(LED_to_duty) 2e108 // @0a5 #386: STORE(s1,PWM_channel7) 34014 // @0a6 #387: JUMP(warm_start) // #388: ; // #389: ; // #390: ; Convert LED sequence number into PWM intensity figure // #391: ; // #392: ; LEDs duty cycle values are 0,1,2,4,8,16,32 and 64 because they appear to give what // #393: ; appears to be a fairly liner change in intensity and provides a simple way to set // #394: ; the duty value. // #395: ; // #396: ; Provide sequence value in register s0 and intensity will be // #397: ; returned in register s1. // #398: ; // #399: ; s0 s1 // #400: ; 00 00 // #401: ; 01 01 // #402: ; 02 02 // #403: ; 03 04 // #404: ; 04 08 // #405: ; 05 10 // #406: ; 06 20 // #407: ; 07 40 // #408: ; 08 80 // #409: ; 09 40 // #410: ; 0A 20 // #411: ; 0B 10 // #412: ; 0C 08 // #413: ; 0D 04 // #414: ; 0E 02 // #415: ; 0F 01 // #416: ; 10 00 and zero for all larger values of s0 // #417: ; // @0a7 #418: [LED_to_duty] 00100 // @0a7 #418: LOAD(s1,0) 14000 // @0a8 #419: COMPARE(s0,0) ;test for zero 2b000 // @0a9 #420: RETURN(Z) 00101 // @0aa #421: LOAD(s1,1) ;inject '1' // @0ab #422: [go_up_loop] 1c001 // @0ab #422: SUB(s0,1) 2b000 // @0ac #423: RETURN(Z) 20106 // @0ad #424: SL0(s1) ;multiply by 2 358b0 // @0ae #425: JUMP(C,go_down) 340ab // @0af #426: JUMP(go_up_loop) // @0b0 #427: [go_down] 00140 // @0b0 #427: LOAD(s1,64) // @0b1 #428: [go_down_loop] 1c001 // @0b1 #428: SUB(s0,1) 2b000 // @0b2 #429: RETURN(Z) 2010e // @0b3 #430: SR0(s1) ;divide by 2 340b1 // @0b4 #431: JUMP(go_down_loop) // #432: ; // #433: ;************************************************************************************** // #434: ; UART communication routines // #435: ;************************************************************************************** // #436: ; // #437: ; Read one character from the UART // #438: ; // #439: ; Character read will be returned in a register called 'UART_data'. // #440: ; // #441: ; The routine first tests the receiver FIFO buffer to see if data is present. // #442: ; If the FIFO is empty, the routine waits until there is a character to read. // #443: ; As this could take any amount of time the wait loop could include a call to a // #444: ; subroutine which performs a useful function. // #445: ; // #446: ; // #447: ; Registers used s0 and UART_data // #448: ; // @0b5 #449: [read_from_UART] 04000 // @0b5 #449: INPUT(s0,status_port) ;test Rx_FIFO buffer 12004 // @0b6 #450: TEST(s0,rx_data_present) ;wait if empty 354b9 // @0b7 #451: JUMP(NZ,read_character) 340b5 // @0b8 #452: JUMP(read_from_UART) // @0b9 #453: [read_character] 04f01 // @0b9 #453: INPUT(UART_data,UART_read_port) ;read from FIFO 2a000 // @0ba #454: RETURN // #455: ; // #456: ; // #457: ; // #458: ; Transmit one character to the UART // #459: ; // #460: ; Character supplied in register called 'UART_data'. // #461: ; // #462: ; The routine first tests the transmit FIFO buffer to see if it is full. // #463: ; If the FIFO is full, then the routine waits until it there is space. // #464: ; // #465: ; Registers used s0 // #466: ; // @0bb #467: [send_to_UART] 04000 // @0bb #467: INPUT(s0,status_port) ;test Tx_FIFO buffer 12002 // @0bc #468: TEST(s0,tx_full) ;wait if full 350bf // @0bd #469: JUMP(Z,UART_write) 340bb // @0be #470: JUMP(send_to_UART) // @0bf #471: [UART_write] 2cf20 // @0bf #471: OUTPUT(UART_data,UART_write_port) 2a000 // @0c0 #472: RETURN // #473: ; // #474: ; // #475: ; // #476: ;************************************************************************************** // #477: ; Text messages // #478: ;************************************************************************************** // #479: ; // #480: ; // #481: ; Send Carriage Return to the UART // #482: ; // @0c1 #483: [send_CR] 00f0d // @0c1 #483: LOAD(UART_data,character_CR) 300bb // @0c2 #484: CALL(send_to_UART) 2a000 // @0c3 #485: RETURN // #486: ; // #487: ; Send a space to the UART // #488: ; // @0c4 #489: [send_space] 00f20 // @0c4 #489: LOAD(UART_data,character_space) 300bb // @0c5 #490: CALL(send_to_UART) 2a000 // @0c6 #491: RETURN // #492: ; // #493: ; // #494: ; // #495: ; Send 'PicoBlaze Servo Control' string to the UART // #496: ; // @0c7 #497: [send_welcome] 300c1 // @0c7 #497: CALL(send_CR) 300c1 // @0c8 #498: CALL(send_CR) 00f50 // @0c9 #499: LOAD(UART_data,character_P) 300bb // @0ca #500: CALL(send_to_UART) 00f69 // @0cb #501: LOAD(UART_data,character_i) 300bb // @0cc #502: CALL(send_to_UART) 00f63 // @0cd #503: LOAD(UART_data,character_c) 300bb // @0ce #504: CALL(send_to_UART) 00f6f // @0cf #505: LOAD(UART_data,character_o) 300bb // @0d0 #506: CALL(send_to_UART) 00f42 // @0d1 #507: LOAD(UART_data,character_B) 300bb // @0d2 #508: CALL(send_to_UART) 00f6c // @0d3 #509: LOAD(UART_data,character_l) 300bb // @0d4 #510: CALL(send_to_UART) 00f61 // @0d5 #511: LOAD(UART_data,character_a) 300bb // @0d6 #512: CALL(send_to_UART) 00f7a // @0d7 #513: LOAD(UART_data,character_z) 300bb // @0d8 #514: CALL(send_to_UART) 00f65 // @0d9 #515: LOAD(UART_data,character_e) 300bb // @0da #516: CALL(send_to_UART) 300c4 // @0db #517: CALL(send_space) 00f41 // @0dc #518: LOAD(UART_data,character_A) 300bb // @0dd #519: CALL(send_to_UART) 00f75 // @0de #520: LOAD(UART_data,character_u) 300bb // @0df #521: CALL(send_to_UART) 00f74 // @0e0 #522: LOAD(UART_data,character_t) 300bb // @0e1 #523: CALL(send_to_UART) 00f6f // @0e2 #524: LOAD(UART_data,character_o) 300bb // @0e3 #525: CALL(send_to_UART) 300c4 // @0e4 #526: CALL(send_space) 00f50 // @0e5 #527: LOAD(UART_data,character_P) 300bb // @0e6 #528: CALL(send_to_UART) 00f57 // @0e7 #529: LOAD(UART_data,character_W) 300bb // @0e8 #530: CALL(send_to_UART) 00f4d // @0e9 #531: LOAD(UART_data,character_M) 300bb // @0ea #532: CALL(send_to_UART) 300c4 // @0eb #533: CALL(send_space) 00f41 // @0ec #534: LOAD(UART_data,character_A) 300bb // @0ed #535: CALL(send_to_UART) 00f63 // @0ee #536: LOAD(UART_data,character_c) 300bb // @0ef #537: CALL(send_to_UART) 00f74 // @0f0 #538: LOAD(UART_data,character_t) 300bb // @0f1 #539: CALL(send_to_UART) 00f69 // @0f2 #540: LOAD(UART_data,character_i) 300bb // @0f3 #541: CALL(send_to_UART) 00f76 // @0f4 #542: LOAD(UART_data,character_v) 300bb // @0f5 #543: CALL(send_to_UART) 00f65 // @0f6 #544: LOAD(UART_data,character_e) 300bb // @0f7 #545: CALL(send_to_UART) 300c1 // @0f8 #546: CALL(send_CR) 300c1 // @0f9 #547: CALL(send_CR) 2a000 // @0fa #548: RETURN // #549: ; // #550: ; // #551: ;Send 'OK' to the UART // #552: ; // @0fb #553: [send_OK] 300c1 // @0fb #553: CALL(send_CR) 00f4f // @0fc #554: LOAD(UART_data,character_O) 300bb // @0fd #555: CALL(send_to_UART) 00f4b // @0fe #556: LOAD(UART_data,character_K) 300bb // @0ff #557: CALL(send_to_UART) 340c1 // @100 #558: JUMP(send_CR) // #559: ; // #560: ; // #561: ;************************************************************************************** // #562: ; Interrupt Service Routine (ISR) // #563: ;************************************************************************************** // #564: ; // #565: ; Interrupts occur at 3.92us intervals and are used to generate the PWM pulses generated // #566: ; at a PRF of 1KHz. The 3.92us interrupt rate corresponds with a resolution of 256 steps // #567: ; over the 1ms associated with the 1KHz PRF. // #568: ; // #569: ; The ISR is self contained and all registers used are preserved. Scratch pad memory // #570: ; locations are used to determine the desired duty factor for each of 12 channels. // #571: ; // #572: ; Note that an interrupt is generated every 196 clock cycles. This means that there is // #573: ; only time to execute 98 instructions between each interrupt. This ISR is 48 instructions // #574: ; long. A further 3 instructions are also consumed by the interrupt process // #575: ; (abandoned instruction, virtual CALL to 3FF and the interrupt vector JUMP) and hence // #576: ; PicoBlaze has approximately half of its time available for other tasks in the main program. // #577: ; // #578: ; Although a loop would normal be employed in software to process each of 12 channels, // #579: ; the implementation of a loop would increase the number of instructions which needed to // #580: ; be executed to such an extent that this 12 channel implementation would not be possible. // #581: ; Consequently the code is written out in a linear fashion which consumes more program // #582: ; space but which executes faster. // #583: ; // @101 #584: [ISR] 2e00d // @101 #584: STORE(s0,ISR_preserve_s0) ;preserve registers to be used 2e10e // @102 #585: STORE(s1,ISR_preserve_s1) 2e20f // @103 #586: STORE(s2,ISR_preserve_s2) // #587: ;Determine the number of steps currently through the 1ms PWM cycle 06100 // @104 #588: FETCH(s1,PWM_duty_counter) ;read 8-bit counter of steps 18101 // @105 #589: ADD(s1,1) ;increment counter (will roll over to zero) 2e100 // @106 #590: STORE(s1,PWM_duty_counter) ;update count value in memory for next interrupt. // #591: ;Read duty factor for each channel and compare it with the duty counter and set or // #592: ;reset a bit in register s2 accordingly. 0600c // @107 #593: FETCH(s0,PWM_channel11) ;read desired setting of pulse width 15100 // @108 #594: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @109 #595: SLA(s2) ;shift carry into register s2 0600b // @10a #596: FETCH(s0,PWM_channel10) ;read desired setting of pulse width 15100 // @10b #597: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @10c #598: SLA(s2) ;shift carry into register s2 0600a // @10d #599: FETCH(s0,PWM_channel9) ;read desired setting of pulse width 15100 // @10e #600: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @10f #601: SLA(s2) ;shift carry into register s2 06009 // @110 #602: FETCH(s0,PWM_channel8) ;read desired setting of pulse width 15100 // @111 #603: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @112 #604: SLA(s2) ;shift carry into register s2 2c240 // @113 #605: OUTPUT(s2,simple_port) ;drive pins on connector J4 06008 // @114 #606: FETCH(s0,PWM_channel7) ;read desired setting of pulse width 15100 // @115 #607: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @116 #608: SLA(s2) ;shift carry into register s2 06007 // @117 #609: FETCH(s0,PWM_channel6) ;read desired setting of pulse width 15100 // @118 #610: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @119 #611: SLA(s2) ;shift carry into register s2 06006 // @11a #612: FETCH(s0,PWM_channel5) ;read desired setting of pulse width 15100 // @11b #613: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @11c #614: SLA(s2) ;shift carry into register s2 06005 // @11d #615: FETCH(s0,PWM_channel4) ;read desired setting of pulse width 15100 // @11e #616: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @11f #617: SLA(s2) ;shift carry into register s2 06004 // @120 #618: FETCH(s0,PWM_channel3) ;read desired setting of pulse width 15100 // @121 #619: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @122 #620: SLA(s2) ;shift carry into register s2 06003 // @123 #621: FETCH(s0,PWM_channel2) ;read desired setting of pulse width 15100 // @124 #622: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @125 #623: SLA(s2) ;shift carry into register s2 06002 // @126 #624: FETCH(s0,PWM_channel1) ;read desired setting of pulse width 15100 // @127 #625: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @128 #626: SLA(s2) ;shift carry into register s2 06001 // @129 #627: FETCH(s0,PWM_channel0) ;read desired setting of pulse width 15100 // @12a #628: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @12b #629: SLA(s2) ;shift carry into register s2 2c280 // @12c #630: OUTPUT(s2,LED_port) ;drive LEDs 0600d // @12d #631: FETCH(s0,ISR_preserve_s0) ;restore register values 0610e // @12e #632: FETCH(s1,ISR_preserve_s1) 0620f // @12f #633: FETCH(s2,ISR_preserve_s2) 38001 // @130 #634: RETURNI(ENABLE) // #635: ; // #636: ; // #637: ;************************************************************************************** // #638: ; Interrupt Vector // #639: ;************************************************************************************** // #640: ; @3ff // #641: ADDRESS(1023) 34101 // @3ff #642: JUMP(ISR) // #643: ; // #644: ;