/* Symbol Table */ // ASCII_byte_to_hex = LABEL: 151 // ASCII_letter = LABEL: 174 // ASCII_to_hex = LABEL: 164 // BS_edit = LABEL: 116 // IO_command = LABEL: 66 // ISR = LABEL: 279 // ISR_preserve_s0 = CONSTANT: 13 // ISR_preserve_s1 = CONSTANT: 14 // ISR_preserve_s2 = CONSTANT: 15 // LD_command = LABEL: 40 // LED0 = CONSTANT: 1 // LED1 = CONSTANT: 2 // LED2 = CONSTANT: 4 // LED3 = CONSTANT: 8 // LED4 = CONSTANT: 16 // LED5 = CONSTANT: 32 // LED6 = CONSTANT: 64 // LED7 = CONSTANT: 128 // LED_port = CONSTANT: 128 // 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: 97 // UART_write_port = CONSTANT: 32 // bad_command = LABEL: 37 // 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_UART_Rx_loop = LABEL: 128 // cold_start = LABEL: 0 // next_IO_number = LABEL: 76 // onechar_to_value = LABEL: 147 // read_character = LABEL: 91 // read_duty_value = LABEL: 50 // read_error = LABEL: 124 // read_from_UART = LABEL: 87 // read_next_char = LABEL: 84 // receive_full_test = LABEL: 102 // receive_string = LABEL: 99 // 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: 176 // send_Error = LABEL: 263 // send_OK = LABEL: 273 // send_Overflow_Error = LABEL: 246 // send_backspace = LABEL: 182 // send_greater_than = LABEL: 243 // send_prompt = LABEL: 230 // send_space = LABEL: 179 // send_space_Error = LABEL: 262 // send_to_UART = LABEL: 93 // send_welcome = LABEL: 185 // 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 // string_start = CONSTANT: 48 // string_start_again = LABEL: 122 // tx_full = CONSTANT: 2 // tx_half_full = CONSTANT: 1 // ucs_loop = LABEL: 140 // upper_case = LABEL: 133 // upper_case_string = LABEL: 139 // warm_start = LABEL: 26 /* Program Code */ // #1: ; KCPSM3 Program - Pulse Width Modulation (PWM) Control on the Spartan-3E Starter Kit. // #2: ; // #3: ; Ken Chapman - Xilinx Ltd // #4: ; // #5: ; Version v1.00 - 22nd May 2006 // #6: ; // #7: ; Provides control for 12 channels of PWM with a Pulse Repetition Frequency (PRF) of 1KHz // #8: ; and an 8-bit duty cycle resolution (256 steps). Control is provided for each channel // #9: ; via the UART interface to the PC running HyperTerminal or similar to enter simple text // #10: ; commands. // #11: ; // #12: ;************************************************************************************** // #13: ; Port definitions // #14: ;************************************************************************************** // #15: ; // #16: ; // #17: ; // #18: CONSTANT(LED_port,128) ;8 simple LEDs // #19: CONSTANT(LED0,1) ; LED 0 - bit0 // #20: CONSTANT(LED1,2) ; 1 - bit1 // #21: CONSTANT(LED2,4) ; 2 - bit2 // #22: CONSTANT(LED3,8) ; 3 - bit3 // #23: CONSTANT(LED4,16) ; 4 - bit4 // #24: CONSTANT(LED5,32) ; 5 - bit5 // #25: CONSTANT(LED6,64) ; 6 - bit6 // #26: CONSTANT(LED7,128) ; 7 - bit7 // #27: ; // #28: ; // #29: CONSTANT(simple_port,64) ;4 simple outputs // #30: CONSTANT(simple_IO9,1) ; Header IO9 - bit0 // #31: CONSTANT(simple_IO10,2) ; IO10 - bit1 // #32: CONSTANT(simple_IO11,4) ; IO11 - bit2 // #33: CONSTANT(simple_IO12,8) ; IO12 - bit3 // #34: ; // #35: ; // #36: ; // #37: CONSTANT(status_port,0) ;UART status input // #38: CONSTANT(tx_half_full,1) ; Transmitter half full - bit0 // #39: CONSTANT(tx_full,2) ; FIFO full - bit1 // #40: CONSTANT(rx_data_present,4) ; Receiver data present - bit2 // #41: CONSTANT(rx_half_full,8) ; FIFO half full - bit3 // #42: CONSTANT(rx_full,16) ; full - bit4 // #43: CONSTANT(spare1,32) ; spare '0' - bit5 // #44: CONSTANT(spare2,64) ; spare '0' - bit6 // #45: CONSTANT(spare3,128) ; spare '0' - bit7 // #46: ; // #47: CONSTANT(UART_read_port,1) ;UART Rx data input // #48: ; // #49: CONSTANT(UART_write_port,32) ;UART Tx data output // #50: ; // #51: ; // #52: ; // #53: ;************************************************************************************** // #54: ; Special Register usage // #55: ;************************************************************************************** // #56: ; // #57: NAMEREG(sF,UART_data) ;used to pass data to and from the UART // #58: ; // #59: ; // #60: ; // #61: ;************************************************************************************** // #62: ;Scratch Pad Memory Locations // #63: ;************************************************************************************** // #64: ; // #65: CONSTANT(PWM_duty_counter,0) ;Duty Counter 0 to 255 within 1KHz period (1ms) // #66: CONSTANT(PWM_channel0,1) ;PWM settings for each channel // #67: CONSTANT(PWM_channel1,2) ; Channels 0 to 7 = LEDs 0 to 7 // #68: CONSTANT(PWM_channel2,3) ; Channels 8 to 11 = IO9 to IO12 // #69: CONSTANT(PWM_channel3,4) // #70: CONSTANT(PWM_channel4,5) // #71: CONSTANT(PWM_channel5,6) // #72: CONSTANT(PWM_channel6,7) // #73: CONSTANT(PWM_channel7,8) // #74: CONSTANT(PWM_channel8,9) // #75: CONSTANT(PWM_channel9,10) // #76: CONSTANT(PWM_channel10,11) // #77: CONSTANT(PWM_channel11,12) // #78: CONSTANT(ISR_preserve_s0,13) ;preserve register contents during Interrupt Service Routine // #79: CONSTANT(ISR_preserve_s1,14) // #80: CONSTANT(ISR_preserve_s2,15) // #81: ; // #82: ; // #83: ; // #84: ; // #85: ;UART character strings will be stored in scratch pad memory ending in carriage return. // #86: ;A string can be up to 16 characters with the start location defined by this constant. // #87: ; // #88: CONSTANT(string_start,48) // #89: ; // #90: ; // #91: ; // #92: ;************************************************************************************** // #93: ;Useful data constants // #94: ;************************************************************************************** // #95: ; // #96: ; // #97: ; // #98: ; // #99: ;ASCII table // #100: ; // #101: CONSTANT(character_a,97) // #102: CONSTANT(character_b,98) // #103: CONSTANT(character_c,99) // #104: CONSTANT(character_d,100) // #105: CONSTANT(character_e,101) // #106: CONSTANT(character_f,102) // #107: CONSTANT(character_g,103) // #108: CONSTANT(character_h,104) // #109: CONSTANT(character_i,105) // #110: CONSTANT(character_j,106) // #111: CONSTANT(character_k,107) // #112: CONSTANT(character_l,108) // #113: CONSTANT(character_m,109) // #114: CONSTANT(character_n,110) // #115: CONSTANT(character_o,111) // #116: CONSTANT(character_p,112) // #117: CONSTANT(character_q,113) // #118: CONSTANT(character_r,114) // #119: CONSTANT(character_s,115) // #120: CONSTANT(character_t,116) // #121: CONSTANT(character_u,117) // #122: CONSTANT(character_v,118) // #123: CONSTANT(character_w,119) // #124: CONSTANT(character_x,120) // #125: CONSTANT(character_y,121) // #126: CONSTANT(character_z,122) // #127: CONSTANT(character_A,65) // #128: CONSTANT(character_B,66) // #129: CONSTANT(character_C,67) // #130: CONSTANT(character_D,68) // #131: CONSTANT(character_E,69) // #132: CONSTANT(character_F,70) // #133: CONSTANT(character_G,71) // #134: CONSTANT(character_H,72) // #135: CONSTANT(character_I,73) // #136: CONSTANT(character_J,74) // #137: CONSTANT(character_K,75) // #138: CONSTANT(character_L,76) // #139: CONSTANT(character_M,77) // #140: CONSTANT(character_N,78) // #141: CONSTANT(character_O,79) // #142: CONSTANT(character_P,80) // #143: CONSTANT(character_Q,81) // #144: CONSTANT(character_R,82) // #145: CONSTANT(character_S,83) // #146: CONSTANT(character_T,84) // #147: CONSTANT(character_U,85) // #148: CONSTANT(character_V,86) // #149: CONSTANT(character_W,87) // #150: CONSTANT(character_X,88) // #151: CONSTANT(character_Y,89) // #152: CONSTANT(character_Z,90) // #153: CONSTANT(character_0,48) // #154: CONSTANT(character_1,49) // #155: CONSTANT(character_2,50) // #156: CONSTANT(character_3,51) // #157: CONSTANT(character_4,52) // #158: CONSTANT(character_5,53) // #159: CONSTANT(character_6,54) // #160: CONSTANT(character_7,55) // #161: CONSTANT(character_8,56) // #162: CONSTANT(character_9,57) // #163: CONSTANT(character_colon,58) // #164: CONSTANT(character_stop,46) // #165: CONSTANT(character_semi_colon,59) // #166: CONSTANT(character_minus,45) // #167: CONSTANT(character_divide,47) ;'/' // #168: CONSTANT(character_plus,43) // #169: CONSTANT(character_comma,44) // #170: CONSTANT(character_less_than,60) // #171: CONSTANT(character_greater_than,62) // #172: CONSTANT(character_equals,61) // #173: CONSTANT(character_space,32) // #174: CONSTANT(character_CR,13) ;carriage return // #175: CONSTANT(character_question,63) ;'?' // #176: CONSTANT(character_dollar,36) // #177: CONSTANT(character_exclaim,33) ;'!' // #178: CONSTANT(character_BS,8) ;Back Space command character // #179: ; // #180: ; // #181: ; // #182: ; // #183: ; // #184: ;************************************************************************************** // #185: ;Initialise the system // #186: ;************************************************************************************** // #187: ; // #188: ; Each PWM channels will be set to a different initial value just for the purposes // #189: ; of demonstration. In practice, the initial duty values will depend on the requirements // #190: ; of a given system but completely off (zero) is normally the safe option. // #191: ; // #192: ; Note that it is difficult to distinguish difference between the intensity of LEDs driven // #193: ; with duty factors more than 40% (40% = 102/256 or 66Hex). So using relatively small values // #194: ; will better demonstrate the PWM control of intensity. // #195: ; // #196: ; Initial values for LEDs give graduated intensity. Large change required for brighter LEDs. // #197: ; // @000 #198: [cold_start] 00005 // @000 #198: LOAD(s0,5) ;5/256 = 2% 2e001 // @001 #199: STORE(s0,PWM_channel0) 0000d // @002 #200: LOAD(s0,13) ;13/256 = 5% 2e002 // @003 #201: STORE(s0,PWM_channel1) 00014 // @004 #202: LOAD(s0,20) ;26/256 = 8% 2e003 // @005 #203: STORE(s0,PWM_channel2) 00026 // @006 #204: LOAD(s0,38) ;38/256 = 15% 2e004 // @007 #205: STORE(s0,PWM_channel3) 00040 // @008 #206: LOAD(s0,64) ;64/256 = 25% 2e005 // @009 #207: STORE(s0,PWM_channel4) 00058 // @00a #208: LOAD(s0,88) ;88/256 = 34% 2e006 // @00b #209: STORE(s0,PWM_channel5) 00080 // @00c #210: LOAD(s0,128) ;128/256 = 50% 2e007 // @00d #211: STORE(s0,PWM_channel6) 000ff // @00e #212: LOAD(s0,FF) ;255/256 = 99.6% Maximum possible 2e008 // @00f #213: STORE(s0,PWM_channel7) // #214: ; // #215: ; Initial values for simple outputs match documentation example // #216: ; 00011 // @010 #217: LOAD(s0,17) ;17/256 = 7% 2e009 // @011 #218: STORE(s0,PWM_channel8) 000bc // @012 #219: LOAD(s0,BC) ;188/256 = 73% 2e00a // @013 #220: STORE(s0,PWM_channel9) 000ef // @014 #221: LOAD(s0,EF) ;239/256 = 93% 2e00b // @015 #222: STORE(s0,PWM_channel10) 00022 // @016 #223: LOAD(s0,34) ;34/256 = 13% 2e00c // @017 #224: STORE(s0,PWM_channel11) // #225: ; 3c001 // @018 #226: ENABLE(INTERRUPT) ;interrupts used to drive servo // #227: ; 300b9 // @019 #228: CALL(send_welcome) ;Write welcome message to UART // #229: ; // #230: ; // #231: ; // #232: ;************************************************************************************** // #233: ; Main program // #234: ;************************************************************************************** // #235: ; // #236: ; Provides a prompt to which an input with one of the following formats is expected... // #237: ; // #238: ; LDn hh // #239: ; // #240: ; IOk hh // #241: ; IOkk hh // #242: ; // #243: ; // #244: ; Where // #245: ; 'LD' is a command to set one of the LED channels. // #246: ; 'IO' is a command to set one of the simple I/O outputs on J4. // #247: ; 'n' is an LED number in the range 0 to 7. // #248: ; 'k' or 'kk' is a simple I/O number in the range 9 to 12. // #249: ; 'hh' is a 2 digit hex value to specify the PWM duty factor (range 00 to FF). // #250: ; // #251: ; The input allows a degree of editing to be performed and upper and lower case letters // #252: ; to be used. // #253: ; // @01a #254: [warm_start] 300e6 // @01a #254: CALL(send_prompt) ;Prompt 'KCPSM3>' 30063 // @01b #255: CALL(receive_string) ;obtain input string of up to 16 characters 3008b // @01c #256: CALL(upper_case_string) ;convert string to upper case // #257: ; 00e30 // @01d #258: LOAD(sE,string_start) ;sE is memory pointer 070e0 // @01e #259: FETCH(s0,sE) ;test for carriage return 1400d // @01f #260: COMPARE(s0,character_CR) 3501a // @020 #261: JUMP(Z,warm_start) 1404c // @021 #262: COMPARE(s0,character_L) ;test for 'L' of 'LD' command 35028 // @022 #263: JUMP(Z,LD_command) 14049 // @023 #264: COMPARE(s0,character_I) ;test for 'I' of 'IO' command 35042 // @024 #265: JUMP(Z,IO_command) // @025 #266: [bad_command] 300b0 // @025 #266: CALL(send_CR) ;no valid command entered 30107 // @026 #267: CALL(send_Error) 3401a // @027 #268: JUMP(warm_start) // #269: ; // #270: ;Processing potential 'LD' command // #271: ; // @028 #272: [LD_command] 30054 // @028 #272: CALL(read_next_char) 14044 // @029 #273: COMPARE(s0,character_D) ;test for 'D' of 'LD' command 35425 // @02a #274: JUMP(NZ,bad_command) 30054 // @02b #275: CALL(read_next_char) ;test for LED number 30093 // @02c #276: CALL(onechar_to_value) 35825 // @02d #277: JUMP(C,bad_command) 14008 // @02e #278: COMPARE(s0,8) ;test for number in range 0 to 7 35c25 // @02f #279: JUMP(NC,bad_command) 01d00 // @030 #280: LOAD(sD,s0) ;convert number into memory pointer in sD 18d01 // @031 #281: ADD(sD,PWM_channel0) // @032 #282: [read_duty_value] 30054 // @032 #282: CALL(read_next_char) ;test for a space 14020 // @033 #283: COMPARE(s0,character_space) 35425 // @034 #284: JUMP(NZ,bad_command) 30054 // @035 #285: CALL(read_next_char) ;read two character hex value 01300 // @036 #286: LOAD(s3,s0) 30054 // @037 #287: CALL(read_next_char) 01200 // @038 #288: LOAD(s2,s0) 30097 // @039 #289: CALL(ASCII_byte_to_hex) ;convert to value in s0 35825 // @03a #290: JUMP(C,bad_command) 01c00 // @03b #291: LOAD(sC,s0) ;remember value 30054 // @03c #292: CALL(read_next_char) ;test for carriage return to end command 1400d // @03d #293: COMPARE(s0,character_CR) 35425 // @03e #294: JUMP(NZ,bad_command) 2fcd0 // @03f #295: STORE(sC,sD) ;store new PWM duty factor for an LED 30111 // @040 #296: CALL(send_OK) 3401a // @041 #297: JUMP(warm_start) // #298: ; // #299: ;Processing potential 'LD' command // #300: ; // @042 #301: [IO_command] 30054 // @042 #301: CALL(read_next_char) 1404f // @043 #302: COMPARE(s0,character_O) ;test for '0' of 'IO' command 35425 // @044 #303: JUMP(NZ,bad_command) 30054 // @045 #304: CALL(read_next_char) ;test for IO number 14031 // @046 #305: COMPARE(s0,character_1) ;first number must either be '1' or '9' 3504c // @047 #306: JUMP(Z,next_IO_number) 14039 // @048 #307: COMPARE(s0,character_9) 35425 // @049 #308: JUMP(NZ,bad_command) 00d09 // @04a #309: LOAD(sD,PWM_channel8) ;IO9 is controlled by PWM channel8 34032 // @04b #310: JUMP(read_duty_value) // @04c #311: [next_IO_number] 30054 // @04c #311: CALL(read_next_char) ;read next number for IO10 to IO12 30093 // @04d #312: CALL(onechar_to_value) 35825 // @04e #313: JUMP(C,bad_command) 14003 // @04f #314: COMPARE(s0,3) ;test for number in range 0 to 2 35c25 // @050 #315: JUMP(NC,bad_command) 01d00 // @051 #316: LOAD(sD,s0) ;convert number into memory pointer in sD 18d0a // @052 #317: ADD(sD,PWM_channel9) 34032 // @053 #318: JUMP(read_duty_value) // #319: ; // #320: ;Read next character from scratch pad memory // #321: ; // @054 #322: [read_next_char] 18e01 // @054 #322: ADD(sE,1) 070e0 // @055 #323: FETCH(s0,sE) ;test for space 2a000 // @056 #324: RETURN // #325: ; // #326: ; // #327: ; // #328: ;************************************************************************************** // #329: ; UART communication routines // #330: ;************************************************************************************** // #331: ; // #332: ; Read one character from the UART // #333: ; // #334: ; Character read will be returned in a register called 'UART_data'. // #335: ; // #336: ; The routine first tests the receiver FIFO buffer to see if data is present. // #337: ; If the FIFO is empty, the routine waits until there is a character to read. // #338: ; As this could take any amount of time the wait loop could include a call to a // #339: ; subroutine which performs a useful function. // #340: ; // #341: ; // #342: ; Registers used s0 and UART_data // #343: ; // @057 #344: [read_from_UART] 04000 // @057 #344: INPUT(s0,status_port) ;test Rx_FIFO buffer 12004 // @058 #345: TEST(s0,rx_data_present) ;wait if empty 3545b // @059 #346: JUMP(NZ,read_character) 34057 // @05a #347: JUMP(read_from_UART) // @05b #348: [read_character] 04f01 // @05b #348: INPUT(UART_data,UART_read_port) ;read from FIFO 2a000 // @05c #349: RETURN // #350: ; // #351: ; // #352: ; // #353: ; Transmit one character to the UART // #354: ; // #355: ; Character supplied in register called 'UART_data'. // #356: ; // #357: ; The routine first tests the transmit FIFO buffer to see if it is full. // #358: ; If the FIFO is full, then the routine waits until it there is space. // #359: ; // #360: ; Registers used s0 // #361: ; // @05d #362: [send_to_UART] 04000 // @05d #362: INPUT(s0,status_port) ;test Tx_FIFO buffer 12002 // @05e #363: TEST(s0,tx_full) ;wait if full 35061 // @05f #364: JUMP(Z,UART_write) 3405d // @060 #365: JUMP(send_to_UART) // @061 #366: [UART_write] 2cf20 // @061 #366: OUTPUT(UART_data,UART_write_port) 2a000 // @062 #367: RETURN // #368: ; // #369: ; // #370: ; // #371: ; // #372: ;Receive ASCII string from UART // #373: ; // #374: ;An ASCII string will be read from the UART and stored in scratch pad memory // #375: ;commencing at the location specified by a constant named 'string_start'. // #376: ;The string will have a maximum length of 16 characters including a // #377: ;carriage return (0D) denoting the end of the string. // #378: ; // #379: ;As each character is read, it is echoed to the UART transmitter. // #380: ;Some minor editing is supported using backspace (BS=08) which is used // #381: ;to adjust what is stored in scratch pad memory and adjust the display // #382: ;on the terminal screen using characters sent to the UART transmitter. // #383: ; // #384: ;A test is made for the receiver FIFO becoming full. A full status is treated as // #385: ;a potential error situation and will result in a 'Overflow Error' message being // #386: ;transmitted to the UART, the receiver FIFO being purged of all data and an // #387: ;empty string being stored (carriage return at first location). // #388: ; // #389: ;Registers used s0, s1, s2 and 'UART_data'. // #390: ; // @063 #391: [receive_string] 00130 // @063 #391: LOAD(s1,string_start) ;locate start of string 01210 // @064 #392: LOAD(s2,s1) ;compute 16 character address 18210 // @065 #393: ADD(s2,16) // @066 #394: [receive_full_test] 04000 // @066 #394: INPUT(s0,status_port) ;test Rx_FIFO buffer for full 12010 // @067 #395: TEST(s0,rx_full) 3547c // @068 #396: JUMP(NZ,read_error) 30057 // @069 #397: CALL(read_from_UART) ;obtain and echo character 3005d // @06a #398: CALL(send_to_UART) 2ff10 // @06b #399: STORE(UART_data,s1) ;write to memory 14f0d // @06c #400: COMPARE(UART_data,character_CR) ;test for end of string 2b000 // @06d #401: RETURN(Z) 14f08 // @06e #402: COMPARE(UART_data,character_BS) ;test for back space 35074 // @06f #403: JUMP(Z,BS_edit) 18101 // @070 #404: ADD(s1,1) ;increment memory pointer 15120 // @071 #405: COMPARE(s1,s2) ;test for pointer exceeding 16 characters 35466 // @072 #406: JUMP(NZ,receive_full_test) ;next character 300b6 // @073 #407: CALL(send_backspace) ;hold end of string position on terminal display // @074 #408: [BS_edit] 1c101 // @074 #408: SUB(s1,1) ;memory pointer back one 14130 // @075 #409: COMPARE(s1,string_start) ;test for under flow 3587a // @076 #410: JUMP(C,string_start_again) 300b3 // @077 #411: CALL(send_space) ;clear character at current position 300b6 // @078 #412: CALL(send_backspace) ;position cursor 34066 // @079 #413: JUMP(receive_full_test) ;next character // @07a #414: [string_start_again] 300f3 // @07a #414: CALL(send_greater_than) ;restore '>' at prompt 34063 // @07b #415: JUMP(receive_string) ;begin again // #416: ;Receiver buffer overflow condition // @07c #417: [read_error] 300b0 // @07c #417: CALL(send_CR) ;Transmit error message 2ef30 // @07d #418: STORE(UART_data,string_start) ;empty string in memory (start with CR) 300f6 // @07e #419: CALL(send_Overflow_Error) 300b0 // @07f #420: CALL(send_CR) // @080 #421: [clear_UART_Rx_loop] 04000 // @080 #421: INPUT(s0,status_port) ;test Rx_FIFO buffer for data 12004 // @081 #422: TEST(s0,rx_data_present) 2b000 // @082 #423: RETURN(Z) ;finish when buffer is empty 04f01 // @083 #424: INPUT(UART_data,UART_read_port) ;read from FIFO and ignore 34080 // @084 #425: JUMP(clear_UART_Rx_loop) // #426: ; // #427: ; // #428: ;************************************************************************************** // #429: ; Useful ASCII conversion and handling routines // #430: ;************************************************************************************** // #431: ; // #432: ; // #433: ; // #434: ; Convert character to upper case // #435: ; // #436: ; The character supplied in register s0. // #437: ; If the character is in the range 'a' to 'z', it is converted // #438: ; to the equivalent upper case character in the range 'A' to 'Z'. // #439: ; All other characters remain unchanged. // #440: ; // #441: ; Registers used s0. // #442: ; // @085 #443: [upper_case] 14061 // @085 #443: COMPARE(s0,97) ;eliminate character codes below 'a' (61 hex) 2b800 // @086 #444: RETURN(C) 1407b // @087 #445: COMPARE(s0,123) ;eliminate character codes above 'z' (7A hex) 2bc00 // @088 #446: RETURN(NC) 0a0df // @089 #447: AND(s0,DF) ;mask bit5 to convert to upper case 2a000 // @08a #448: RETURN // #449: ; // #450: ; // #451: ; // #452: ; Convert string held in scratch pad memory to upper case. // #453: ; // #454: ; Registers used s0, s1 // #455: ; // @08b #456: [upper_case_string] 00130 // @08b #456: LOAD(s1,string_start) // @08c #457: [ucs_loop] 07010 // @08c #457: FETCH(s0,s1) 1400d // @08d #458: COMPARE(s0,character_CR) 2b000 // @08e #459: RETURN(Z) 30085 // @08f #460: CALL(upper_case) 2f010 // @090 #461: STORE(s0,s1) 18101 // @091 #462: ADD(s1,1) 3408c // @092 #463: JUMP(ucs_loop) // #464: ; // #465: ; // #466: ; Convert character '0' to '9' to numerical value in range 0 to 9 // #467: ; // #468: ; The character supplied in register s0. If the character is in the // #469: ; range '0' to '9', it is converted to the equivalent decimal value. // #470: ; Characters not in the range '0' to '9' are signified by the return // #471: ; with the CARRY flag set. // #472: ; // #473: ; Registers used s0. // #474: ; // @093 #475: [onechar_to_value] 180c6 // @093 #475: ADD(s0,C6) ;reject character codes above '9' (39 hex) 2b800 // @094 #476: RETURN(C) ;carry flag is set 1c0f6 // @095 #477: SUB(s0,F6) ;reject character codes below '0' (30 hex) 2a000 // @096 #478: RETURN ;carry is set if value not in range // #479: ; // #480: ; // #481: ; // #482: ; Convert the HEX ASCII characters contained in 's3' and 's2' into // #483: ; an equivalent hexadecimal value in register 's0'. // #484: ; The upper nibble is represented by an ASCII character in register s3. // #485: ; The lower nibble is represented by an ASCII character in register s2. // #486: ; // #487: ; Input characters must be in the range 00 to FF hexadecimal or the CARRY flag // #488: ; will be set on return. // #489: ; // #490: ; Registers used s0, s2 and s3. // #491: ; // @097 #492: [ASCII_byte_to_hex] 01030 // @097 #492: LOAD(s0,s3) ;Take upper nibble 300a4 // @098 #493: CALL(ASCII_to_hex) ;convert to value 2b800 // @099 #494: RETURN(C) ;reject if out of range 01300 // @09a #495: LOAD(s3,s0) ;remember value 20306 // @09b #496: SL0(s3) ;multiply value by 16 to put in upper nibble 20306 // @09c #497: SL0(s3) 20306 // @09d #498: SL0(s3) 20306 // @09e #499: SL0(s3) 01020 // @09f #500: LOAD(s0,s2) ;Take lower nibble 300a4 // @0a0 #501: CALL(ASCII_to_hex) ;convert to value 2b800 // @0a1 #502: RETURN(C) ;reject if out of range 0d030 // @0a2 #503: OR(s0,s3) ;merge in the upper nibble with CARRY reset 2a000 // @0a3 #504: RETURN // #505: ; // #506: ; // #507: ; Routine to convert ASCII data in 's0' to an equivalent HEX value. // #508: ; // #509: ; If character is not valid for hex, then CARRY is set on return. // #510: ; // #511: ; Register used s0 // #512: ; // @0a4 #513: [ASCII_to_hex] 180b9 // @0a4 #513: ADD(s0,B9) ;test for above ASCII code 46 ('F') 2b800 // @0a5 #514: RETURN(C) 1c0e9 // @0a6 #515: SUB(s0,E9) ;normalise 0 to 9 with A-F in 11 to 16 hex 2b800 // @0a7 #516: RETURN(C) ;reject below ASCII code 30 ('0') 1c011 // @0a8 #517: SUB(s0,17) ;isolate A-F down to 00 to 05 hex 35cae // @0a9 #518: JUMP(NC,ASCII_letter) 18007 // @0aa #519: ADD(s0,7) ;test for above ASCII code 46 ('F') 2b800 // @0ab #520: RETURN(C) 1c0f6 // @0ac #521: SUB(s0,F6) ;convert to range 00 to 09 2a000 // @0ad #522: RETURN // @0ae #523: [ASCII_letter] 1800a // @0ae #523: ADD(s0,10) ;convert to range 0A to 0F 2a000 // @0af #524: RETURN // #525: ; // #526: ; // #527: ; // #528: ;************************************************************************************** // #529: ; Text messages // #530: ;************************************************************************************** // #531: ; // #532: ; // #533: ; Send Carriage Return to the UART // #534: ; // @0b0 #535: [send_CR] 00f0d // @0b0 #535: LOAD(UART_data,character_CR) 3005d // @0b1 #536: CALL(send_to_UART) 2a000 // @0b2 #537: RETURN // #538: ; // #539: ; Send a space to the UART // #540: ; // @0b3 #541: [send_space] 00f20 // @0b3 #541: LOAD(UART_data,character_space) 3005d // @0b4 #542: CALL(send_to_UART) 2a000 // @0b5 #543: RETURN // #544: ; // #545: ; // #546: ; // #547: ;Send a back space to the UART // #548: ; // @0b6 #549: [send_backspace] 00f08 // @0b6 #549: LOAD(UART_data,character_BS) 3005d // @0b7 #550: CALL(send_to_UART) 2a000 // @0b8 #551: RETURN // #552: ; // #553: ; // #554: ; Send 'PicoBlaze Servo Control' string to the UART // #555: ; // @0b9 #556: [send_welcome] 300b0 // @0b9 #556: CALL(send_CR) 300b0 // @0ba #557: CALL(send_CR) 00f50 // @0bb #558: LOAD(UART_data,character_P) 3005d // @0bc #559: CALL(send_to_UART) 00f69 // @0bd #560: LOAD(UART_data,character_i) 3005d // @0be #561: CALL(send_to_UART) 00f63 // @0bf #562: LOAD(UART_data,character_c) 3005d // @0c0 #563: CALL(send_to_UART) 00f6f // @0c1 #564: LOAD(UART_data,character_o) 3005d // @0c2 #565: CALL(send_to_UART) 00f42 // @0c3 #566: LOAD(UART_data,character_B) 3005d // @0c4 #567: CALL(send_to_UART) 00f6c // @0c5 #568: LOAD(UART_data,character_l) 3005d // @0c6 #569: CALL(send_to_UART) 00f61 // @0c7 #570: LOAD(UART_data,character_a) 3005d // @0c8 #571: CALL(send_to_UART) 00f7a // @0c9 #572: LOAD(UART_data,character_z) 3005d // @0ca #573: CALL(send_to_UART) 00f65 // @0cb #574: LOAD(UART_data,character_e) 3005d // @0cc #575: CALL(send_to_UART) 300b3 // @0cd #576: CALL(send_space) 00f50 // @0ce #577: LOAD(UART_data,character_P) 3005d // @0cf #578: CALL(send_to_UART) 00f57 // @0d0 #579: LOAD(UART_data,character_W) 3005d // @0d1 #580: CALL(send_to_UART) 00f4d // @0d2 #581: LOAD(UART_data,character_M) 3005d // @0d3 #582: CALL(send_to_UART) 300b3 // @0d4 #583: CALL(send_space) 00f43 // @0d5 #584: LOAD(UART_data,character_C) 3005d // @0d6 #585: CALL(send_to_UART) 00f6f // @0d7 #586: LOAD(UART_data,character_o) 3005d // @0d8 #587: CALL(send_to_UART) 00f6e // @0d9 #588: LOAD(UART_data,character_n) 3005d // @0da #589: CALL(send_to_UART) 00f74 // @0db #590: LOAD(UART_data,character_t) 3005d // @0dc #591: CALL(send_to_UART) 00f72 // @0dd #592: LOAD(UART_data,character_r) 3005d // @0de #593: CALL(send_to_UART) 00f6f // @0df #594: LOAD(UART_data,character_o) 3005d // @0e0 #595: CALL(send_to_UART) 00f6c // @0e1 #596: LOAD(UART_data,character_l) 3005d // @0e2 #597: CALL(send_to_UART) 300b0 // @0e3 #598: CALL(send_CR) 300b0 // @0e4 #599: CALL(send_CR) 2a000 // @0e5 #600: RETURN // #601: ; // #602: ; // #603: ;Send 'KCPSM3>' prompt to the UART // #604: ; // @0e6 #605: [send_prompt] 300b0 // @0e6 #605: CALL(send_CR) ;start new line 00f4b // @0e7 #606: LOAD(UART_data,character_K) 3005d // @0e8 #607: CALL(send_to_UART) 00f43 // @0e9 #608: LOAD(UART_data,character_C) 3005d // @0ea #609: CALL(send_to_UART) 00f50 // @0eb #610: LOAD(UART_data,character_P) 3005d // @0ec #611: CALL(send_to_UART) 00f53 // @0ed #612: LOAD(UART_data,character_S) 3005d // @0ee #613: CALL(send_to_UART) 00f4d // @0ef #614: LOAD(UART_data,character_M) 3005d // @0f0 #615: CALL(send_to_UART) 00f33 // @0f1 #616: LOAD(UART_data,character_3) 3005d // @0f2 #617: CALL(send_to_UART) // #618: ; // #619: ;Send '>' character to the UART // #620: ; // @0f3 #621: [send_greater_than] 00f3e // @0f3 #621: LOAD(UART_data,character_greater_than) 3005d // @0f4 #622: CALL(send_to_UART) 2a000 // @0f5 #623: RETURN // #624: ; // #625: ; // #626: ;Send 'Overflow Error' to the UART // #627: ; // @0f6 #628: [send_Overflow_Error] 00f4f // @0f6 #628: LOAD(UART_data,character_O) 3005d // @0f7 #629: CALL(send_to_UART) 00f76 // @0f8 #630: LOAD(UART_data,character_v) 3005d // @0f9 #631: CALL(send_to_UART) 00f65 // @0fa #632: LOAD(UART_data,character_e) 3005d // @0fb #633: CALL(send_to_UART) 00f72 // @0fc #634: LOAD(UART_data,character_r) 3005d // @0fd #635: CALL(send_to_UART) 00f66 // @0fe #636: LOAD(UART_data,character_f) 3005d // @0ff #637: CALL(send_to_UART) 00f6c // @100 #638: LOAD(UART_data,character_l) 3005d // @101 #639: CALL(send_to_UART) 00f6f // @102 #640: LOAD(UART_data,character_o) 3005d // @103 #641: CALL(send_to_UART) 00f77 // @104 #642: LOAD(UART_data,character_w) 3005d // @105 #643: CALL(send_to_UART) // @106 #644: [send_space_Error] 300b3 // @106 #644: CALL(send_space) // #645: ; // #646: ;Send 'Error' to the UART // #647: ; // @107 #648: [send_Error] 00f45 // @107 #648: LOAD(UART_data,character_E) 3005d // @108 #649: CALL(send_to_UART) 00f72 // @109 #650: LOAD(UART_data,character_r) 3005d // @10a #651: CALL(send_to_UART) 3005d // @10b #652: CALL(send_to_UART) 00f6f // @10c #653: LOAD(UART_data,character_o) 3005d // @10d #654: CALL(send_to_UART) 00f72 // @10e #655: LOAD(UART_data,character_r) 3005d // @10f #656: CALL(send_to_UART) 340b0 // @110 #657: JUMP(send_CR) // #658: ; // #659: ; // #660: ;Send 'OK' to the UART // #661: ; // @111 #662: [send_OK] 300b0 // @111 #662: CALL(send_CR) 00f4f // @112 #663: LOAD(UART_data,character_O) 3005d // @113 #664: CALL(send_to_UART) 00f4b // @114 #665: LOAD(UART_data,character_K) 3005d // @115 #666: CALL(send_to_UART) 340b0 // @116 #667: JUMP(send_CR) // #668: ; // #669: ; // #670: ;************************************************************************************** // #671: ; Interrupt Service Routine (ISR) // #672: ;************************************************************************************** // #673: ; // #674: ; Interrupts occur at 3.92us intervals and are used to generate the PWM pulses generated // #675: ; at a PRF of 1KHz. The 3.92us interrupt rate corresponds with a resolution of 256 steps // #676: ; over the 1ms associated with the 1KHz PRF. // #677: ; // #678: ; The ISR is self contained and all registers used are preserved. Scratch pad memory // #679: ; locations are used to determine the desired duty factor for each of 12 channels. // #680: ; // #681: ; Note that an interrupt is generated every 196 clock cycles. This means that there is // #682: ; only time to execute 98 instructions between each interrupt. This ISR is 48 instructions // #683: ; long. A further 3 instructions are also consumed by the interrupt process // #684: ; (abandoned instruction, virtual CALL to 3FF and the interrupt vector JUMP) and hence // #685: ; PicoBlaze has approximately half of its time available for other tasks in the main program. // #686: ; // #687: ; Although a loop would normal be employed in software to process each of 12 channels, // #688: ; the implementation of a loop would increase the number of instructions which needed to // #689: ; be executed to such an extent that this 12 channel implementation would not be possible. // #690: ; Consequently the code is written out in a linear fashion which consumes more program // #691: ; space but which executes faster. // #692: ; // @117 #693: [ISR] 2e00d // @117 #693: STORE(s0,ISR_preserve_s0) ;preserve registers to be used 2e10e // @118 #694: STORE(s1,ISR_preserve_s1) 2e20f // @119 #695: STORE(s2,ISR_preserve_s2) // #696: ;Determine the number of steps currently through the 1ms PWM cycle 06100 // @11a #697: FETCH(s1,PWM_duty_counter) ;read 8-bit counter of steps 18101 // @11b #698: ADD(s1,1) ;increment counter (will roll over to zero) 2e100 // @11c #699: STORE(s1,PWM_duty_counter) ;update count value in memory for next interrupt. // #700: ;Read duty factor for each channel and compare it with the duty counter and set or // #701: ;reset a bit in register s2 accordingly. 0600c // @11d #702: FETCH(s0,PWM_channel11) ;read desired setting of pulse width 15100 // @11e #703: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @11f #704: SLA(s2) ;shift carry into register s2 0600b // @120 #705: FETCH(s0,PWM_channel10) ;read desired setting of pulse width 15100 // @121 #706: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @122 #707: SLA(s2) ;shift carry into register s2 0600a // @123 #708: FETCH(s0,PWM_channel9) ;read desired setting of pulse width 15100 // @124 #709: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @125 #710: SLA(s2) ;shift carry into register s2 06009 // @126 #711: FETCH(s0,PWM_channel8) ;read desired setting of pulse width 15100 // @127 #712: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @128 #713: SLA(s2) ;shift carry into register s2 2c240 // @129 #714: OUTPUT(s2,simple_port) ;drive pins on connector J4 06008 // @12a #715: FETCH(s0,PWM_channel7) ;read desired setting of pulse width 15100 // @12b #716: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @12c #717: SLA(s2) ;shift carry into register s2 06007 // @12d #718: FETCH(s0,PWM_channel6) ;read desired setting of pulse width 15100 // @12e #719: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @12f #720: SLA(s2) ;shift carry into register s2 06006 // @130 #721: FETCH(s0,PWM_channel5) ;read desired setting of pulse width 15100 // @131 #722: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @132 #723: SLA(s2) ;shift carry into register s2 06005 // @133 #724: FETCH(s0,PWM_channel4) ;read desired setting of pulse width 15100 // @134 #725: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @135 #726: SLA(s2) ;shift carry into register s2 06004 // @136 #727: FETCH(s0,PWM_channel3) ;read desired setting of pulse width 15100 // @137 #728: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @138 #729: SLA(s2) ;shift carry into register s2 06003 // @139 #730: FETCH(s0,PWM_channel2) ;read desired setting of pulse width 15100 // @13a #731: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @13b #732: SLA(s2) ;shift carry into register s2 06002 // @13c #733: FETCH(s0,PWM_channel1) ;read desired setting of pulse width 15100 // @13d #734: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @13e #735: SLA(s2) ;shift carry into register s2 06001 // @13f #736: FETCH(s0,PWM_channel0) ;read desired setting of pulse width 15100 // @140 #737: COMPARE(s1,s0) ;set carry flag if duty factor > duty counter 20200 // @141 #738: SLA(s2) ;shift carry into register s2 2c280 // @142 #739: OUTPUT(s2,LED_port) ;drive LEDs 0600d // @143 #740: FETCH(s0,ISR_preserve_s0) ;restore register values 0610e // @144 #741: FETCH(s1,ISR_preserve_s1) 0620f // @145 #742: FETCH(s2,ISR_preserve_s2) 38001 // @146 #743: RETURNI(ENABLE) // #744: ; // #745: ; // #746: ;************************************************************************************** // #747: ; Interrupt Vector // #748: ;************************************************************************************** // #749: ; @3ff // #750: ADDRESS(1023) 34117 // @3ff #751: JUMP(ISR) // #752: ; // #753: ;