; ; KCPSM3 Program - Picoblaze controller with with UART communication ; and LEDs, buttons, switches ; ; Kai Mueller - University Bremerhaven ; based on sample software by Ken Chapman - Xilinx Ltd - October 2003 ; ; Rev. 17-FEB-2007: initial coding ; for use in DMP course at Univ. Bremerhaven ; ; Rev. 17-MAY-2008: external. off-board signals added ; ; Rev. 17-OCT-2009: modified as PicoTool initial program ; ; ; Port definitions ; ;-- Inputs ---------------------------------------------------- CONSTANT UARTstatus_port, 00 ; UART status input CONSTANT UARTread_port, 01 ; UART Rx data input ; CONSTANT LCD_input_port, 02 ;LCD character module input data CONSTANT BTNSWITCH_port, 03 ; button input CONSTANT EXTERN_port, 04 ; off-board port ; ;-- Outputs ---------------------------------------------------- CONSTANT LED_port, 00 ; LEDs output ; CONSTANT UARTwrite_port, 01 ; UART Tx data output ; CONSTANT LCD_output_port, 02 ;LCD character module output data and control ;-- UART definitions ------------------------------------------ CONSTANT TX_half_full, 01 ; Transmitter half full - bit0 CONSTANT tx_full, 02 ; FIFO full - bit1 CONSTANT rx_half_full, 04 ; Receiver half full - bit2 CONSTANT rx_full, 08 ; FIFO full - bit3 CONSTANT rx_data_present, 10 ; data present - bit4 ; switch definitions CONSTANT switch0, 01 ; Switches SW0 - bit0 CONSTANT switch1, 02 ; SW1 - bit1 CONSTANT switch2, 04 ; SW2 - bit2 CONSTANT switch3, 08 ; SW3 - bit3 CONSTANT BTN_east, 10 ; Buttons East - bit4 CONSTANT BTN_south, 20 ; South - bit5 CONSTANT BTN_north, 40 ; North - bit6 CONSTANT BTN_west, 80 ; West - bit7 ; ; LCD definitions ; -- output bits CONSTANT LCD_E, 01 ; active High Enable E - bit0 CONSTANT LCD_RW, 02 ; Read=1 Write=0 RW - bit1 CONSTANT LCD_RS, 04 ; Instruction=0 Data=1 RS - bit2 CONSTANT LCD_drive, 08 ; Master enable (active High) - bit3 CONSTANT LCD_DB4, 10 ; 4-bit Data DB4 - bit4 CONSTANT LCD_DB5, 20 ; interface Data DB5 - bit5 CONSTANT LCD_DB6, 40 ; Data DB6 - bit6 CONSTANT LCD_DB7, 80 ; Data DB7 - bit7 ; -- input bits (unsed at this time) CONSTANT LCD_read_spare0, 01 ; Spare bits - bit0 CONSTANT LCD_read_spare1, 02 ; are zero - bit1 CONSTANT LCD_read_spare2, 04 ; - bit2 CONSTANT LCD_read_spare3, 08 ; - bit3 CONSTANT LCD_read_DB4, 10 ; 4-bit Data DB4 - bit4 CONSTANT LCD_read_DB5, 20 ; interface Data DB5 - bit5 CONSTANT LCD_read_DB6, 40 ; Data DB6 - bit6 CONSTANT LCD_read_DB7, 80 ; Data DB7 - bit7 ; ;Constant to define a software delay of 1us. This must be adjusted to reflect the ;clock applied to KCPSM3. Every instruction executes in 2 clock cycles making the ;calculation highly predictable. The '6' in the following equation even allows for ;'CALL delay_1us' instruction in the initiating code. ; ; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz ; ;Example: For a 50MHz clock the constant value is (10-6)/4 = 11 (0B Hex). ;For clock rates below 10MHz the value of 1 must be used and the operation will ;become lower than intended. ; CONSTANT delay_1us_constant, 0B ; ; ; Special Register usage ; NAMEREG sF, UART_data ; used to pass UART data NAMEREG sE, ISR_data ; used to pass data to ISR NAMEREG sA, EXT_data ; used for setting ext. port ; ; ; Scratch Pad Memory Locations CONSTANT ISR_preserve_s0, 00 ; Preserve s0 contents during ISR CONSTANT ISR_counter, 01 ; counts ISR calls CONSTANT STR_start, 20 ; Strings start here ; ; Initialize the system ; ; cold_start: CALL LCD_reset ; UART is not functional immediately after reset, ; the LCD_reset routine give enough time for UART initialization ; LOAD EXT_data, 00 LOAD s0, 00 STORE s0, ISR_counter ; set to zero ENABLE INTERRUPT INPUT s0, UARTread_port ; dummy read clear fifo INPUT s0, UARTstatus_port ; dummy read on status reg ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; ---- main loop goes here -------------------------------------------------- ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- redo_start: CALL SendPrompt tst_uart_data: INPUT s0, UARTstatus_port ;test Tx_FIFO buffer TEST s0, rx_data_present JUMP NZ, uart_rx_dat ; no data, perform some background processing (task 0) INPUT s0, BTNSWITCH_port TEST s0, 20 ; south button JUMP Z, bg_dataset LOAD ISR_data, 00 JUMP bg_task1 bg_dataset: LOAD ISR_data, ff bg_task1: FETCH s0, ISR_counter COMPARE s0, 00 JUMP NZ, bgt_1 CALL dispPicoT JUMP bg_endtask bgt_1: COMPARE s0, 80 JUMP NZ, bg_endtask CALL dispIAEHS bg_endtask: JUMP tst_uart_data ; --- end of background tasks uart_rx_dat: INPUT UART_data, UARTread_port ;read from FIFO ; set or clear external pins COMPARE UART_data, CHRASC_0 JUMP NZ, cmdx_0 OR EXT_data, 01 ; set bit 0 cmdx_0: COMPARE UART_data, CHRASC_1 JUMP NZ, cmdx_1 OR EXT_data, 02 ; set bit 1 cmdx_1: COMPARE UART_data, CHRASC_2 JUMP NZ, cmdx_2 AND EXT_data, 02 ; clr bit 0 cmdx_2: COMPARE UART_data, CHRASC_3 JUMP NZ, cmdx_3 AND EXT_data, 01 ; clr bit 1 cmdx_3: OUTPUT EXT_data, EXTERN_port CALL send_to_UART JUMP redo_start ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; ---- End of main programm ------------------------------------------------- ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- send_to_UART: INPUT s0, UARTstatus_port ;test Tx_FIFO buffer TEST s0, tx_full JUMP NZ, send_to_UART OUTPUT UART_data, UARTwrite_port RETURN ; ; Send Carriage Return to the UART ; send_CR: LOAD UART_data, CHRASC_CR JUMP send_to_UART ; implicit "Return" SendPrompt: CALL send_CR ;start new line LOAD UART_data, CHRASCl_i CALL send_to_UART LOAD UART_data, CHRASCl_a CALL send_to_UART LOAD UART_data, CHRASCl_e CALL send_to_UART LOAD UART_data, CHRASC_slash CALL send_to_UART LOAD UART_data, CHRASCl_x CALL send_to_UART LOAD UART_data, CHRASC_greater_than CALL send_to_UART LOAD UART_data, CHRASC_greater_than CALL send_to_UART LOAD UART_data, CHRASC_space CALL send_to_UART RETURN ; ; ; ************************************************************** ; LCD text messages ; ************************************************************** ; ;write PicoTool V0.2b message to LCD dispPicoT: LOAD s7, STR_start ; char* s7 LOAD s6, 20 ; clear display (bit 5) ; line 0 (bit 4) ; position 0 (bits [3..0] CALL PUSH_string LOAD s6, CHRASCu_P CALL PUSH_string LOAD s6, CHRASCl_i CALL PUSH_string LOAD s6, CHRASCl_c CALL PUSH_string LOAD s6, CHRASCl_o CALL PUSH_string LOAD s6, CHRASCu_T CALL PUSH_string LOAD s6, CHRASCl_o CALL PUSH_string LOAD s6, CHRASCl_o CALL PUSH_string LOAD s6, CHRASCl_l CALL PUSH_string LOAD s6, 00 ; end of string indicator CALL PUSH_string CALL String2LCD ; --- next line LOAD s7, STR_start ; char* s7 LOAD s6, 10 ; do not clear display (bit 5) ; line 1 (bit 4) ; position 0 (bits [3..0] CALL PUSH_string LOAD s6, CHRASCu_V CALL PUSH_string LOAD s6, CHRASC_0 CALL PUSH_string LOAD s6, CHRASC_dot CALL PUSH_string LOAD s6, CHRASC_2 CALL PUSH_string LOAD s6, CHRASCl_b CALL PUSH_string LOAD s6, 00 ; end of string indicator CALL PUSH_string CALL String2LCD RETURN ;write ESD U. Bremerhaven message to LCD dispIAEHS: LOAD s7, STR_start ; char* s7 LOAD s6, 20 ; clear display (bit 5) ; line 0 (bit 4) ; position 0 (bits [3..0] CALL PUSH_string LOAD s6, CHRASCu_E CALL PUSH_string LOAD s6, CHRASCu_S CALL PUSH_string LOAD s6, CHRASCu_D CALL PUSH_string LOAD s6, 00 ; end of string indicator CALL PUSH_string CALL String2LCD ; --- next line LOAD s7, STR_start ; char* s7 LOAD s6, 10 ; do not clear display (bit 5) ; line 1 (bit 4) ; position 0 (bits [3..0] CALL PUSH_string LOAD s6, CHRASCu_U CALL PUSH_string LOAD s6, CHRASC_dot CALL PUSH_string LOAD s6, CHRASC_space CALL PUSH_string LOAD s6, CHRASCu_B CALL PUSH_string LOAD s6, CHRASCl_r CALL PUSH_string LOAD s6, CHRASCl_e CALL PUSH_string LOAD s6, CHRASCl_m CALL PUSH_string LOAD s6, CHRASCl_e CALL PUSH_string LOAD s6, CHRASCl_r CALL PUSH_string LOAD s6, CHRASCl_h CALL PUSH_string LOAD s6, CHRASCl_a CALL PUSH_string LOAD s6, CHRASCl_v CALL PUSH_string LOAD s6, CHRASCl_e CALL PUSH_string LOAD s6, CHRASCl_n CALL PUSH_string LOAD s6, 00 ; end of string indicator CALL PUSH_string CALL String2LCD RETURN ; ; ; ; string utilities PUSH_string: STORE s6, (s7) ADD s7, 01 RETURN POP_string: FETCH s6, (s7) ADD s7, 01 RETURN ; ; Display string on LCD ; first byte is control byte ; last byte is 00 (end of string) ; String2LCD: LOAD s7, STR_start ; string in scratchpad memory CALL POP_string TEST s6, 20 ; clear display? CALL NZ, LCD_clear TEST s6, 10 ; line 1? JUMP NZ, s2l_1 AND s6, 0F OR s6, 80 ; line 0 JUMP s2l_2 s2l_1: AND s6, 0F OR s6, C0 ; line 1 s2l_2: LOAD s5, s6 CALL LCD_write_inst8 ;instruction write to set cursor ; write string s2l_3: CALL POP_string TEST s6, FF RETURN Z ; we're done LOAD s5, s6 CALL LCD_write_data JUMP s2l_3 ; NO return here! ; ; ;Display a space on LCD at current cursor position ; ; disp_space: LOAD s5, CHRASC_space CALL LCD_write_data RETURN ; ; ; ; ************************************************************** ; Software delay routines ; ************************************************************** ; ; ; ;Delay of 1us. ; ;Constant value defines reflects the clock applied to KCPSM3. Every instruction ;executes in 2 clock cycles making the calculation highly predictable. The '6' in ;the following equation even allows for 'CALL delay_1us' instruction in the initiating code. ; ; delay_1us_constant = (clock_rate - 6)/4 Where 'clock_rate' is in MHz ; ;Registers used s0 ; delay_1us: LOAD s0, delay_1us_constant wait_1us: SUB s0, 01 JUMP NZ, wait_1us RETURN ; ;Delay of 40us. ; ;Registers used s0, s1 ; delay_40us: LOAD s1, 28 ;40 x 1us = 40us wait_40us: CALL delay_1us SUB s1, 01 JUMP NZ, wait_40us RETURN ; ; ;Delay of 1ms. ; ;Registers used s0, s1, s2 ; delay_1ms: LOAD s2, 19 ;25 x 40us = 1ms wait_1ms: CALL delay_40us SUB s2, 01 JUMP NZ, wait_1ms RETURN ; ;Delay of 20ms. ; ;Delay of 20ms used during initialisation. ; ;Registers used s0, s1, s2, s3 ; delay_20ms: LOAD s3, 14 ;20 x 1ms = 20ms wait_20ms: CALL delay_1ms SUB s3, 01 JUMP NZ, wait_20ms RETURN ; ;Delay of approximately 1 second. ; ;Registers used s0, s1, s2, s3, s4 ; delay_1s: LOAD s4, 32 ;50 x 20ms = 1000ms wait_1s: CALL delay_20ms SUB s4, 01 JUMP NZ, wait_1s RETURN ; ; ; ; ************************************************************** ; LCD Character Module Routines ; ************************************************************** ; ;LCD module is a 16 character by 2 line display but all displays are very similar ;The 4-wire data interface will be used (DB4 to DB7). ; ;The LCD modules are relatively slow and software delay loops are used to slow down ;KCPSM3 adequately for the LCD to communicate. The delay routines are provided in ;a different section (see above in this case). ; ; ;Pulse LCD enable signal 'E' high for greater than 230ns (1us is used). ; ;Register s4 should define the current state of the LCD output port. ; ;Registers used s0, s4 ; LCD_pulse_E: XOR s4, LCD_E ;E=1 OUTPUT s4, LCD_output_port CALL delay_1us XOR s4, LCD_E ;E=0 OUTPUT s4, LCD_output_port RETURN ; ;Write 4-bit instruction to LCD display. ; ;The 4-bit instruction should be provided in the upper 4-bits of register s4. ;Note that this routine does not release the master enable but as it is only ;used during initialisation and as part of the 8-bit instruction write it ;should be acceptable. ; ;Registers used s4 ; LCD_write_inst4: AND s4, F8 ;Enable=1 RS=0 Instruction, RW=0 Write, E=0 OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse CALL LCD_pulse_E RETURN ; ; ;Write 8-bit instruction to LCD display. ; ;The 8-bit instruction should be provided in register s5. ;Instructions are written using the following sequence ; Upper nibble ; wait >1us ; Lower nibble ; wait >40us ; ;Registers used s0, s1, s4, s5 ; LCD_write_inst8: LOAD s4, s5 AND s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0 OR s4, LCD_drive ;Enable=1 CALL LCD_write_inst4 ;write upper nibble CALL delay_1us ;wait >1us LOAD s4, s5 ;select lower nibble with SL1 s4 ;Enable=1 SL0 s4 ;RS=0 Instruction SL0 s4 ;RW=0 Write SL0 s4 ;E=0 CALL LCD_write_inst4 ;write lower nibble CALL delay_40us ;wait >40us LOAD s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0 OUTPUT s4, LCD_output_port ;Release master enable RETURN ; ; ; ;Write 8-bit data to LCD display. ; ;The 8-bit data should be provided in register s5. ;Data bytes are written using the following sequence ; Upper nibble ; wait >1us ; Lower nibble ; wait >40us ; ;Registers used s0, s1, s4, s5 ; LCD_write_data: LOAD s4, s5 AND s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0 OR s4, 0C ;Enable=1 RS=1 Data, RW=0 Write, E=0 OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse CALL LCD_pulse_E ;write upper nibble CALL delay_1us ;wait >1us LOAD s4, s5 ;select lower nibble with SL1 s4 ;Enable=1 SL1 s4 ;RS=1 Data SL0 s4 ;RW=0 Write SL0 s4 ;E=0 OUTPUT s4, LCD_output_port ;set up RS and RW >40ns before enable pulse CALL LCD_pulse_E ;write lower nibble CALL delay_40us ;wait >40us LOAD s4, F0 ;Enable=0 RS=0 Instruction, RW=0 Write, E=0 OUTPUT s4, LCD_output_port ;Release master enable RETURN ; ; ; ;Reset and initialise display to communicate using 4-bit data mode ;Includes routine to clear the display. ; ;Requires the 4-bit instructions 3,3,3,2 to be sent with suitable delays ;following by the 8-bit instructions to set up the display. ; ; 28 = '001' Function set, '0' 4-bit mode, '1' 2-line, '0' 5x7 dot matrix, 'xx' ; 06 = '000001' Entry mode, '1' increment, '0' no display shift ; 0C = '00001' Display control, '1' display on, '0' cursor off, '0' cursor blink off ; 01 = '00000001' Display clear ; ;Registers used s0, s1, s2, s3, s4, s5 ; LCD_reset: CALL delay_20ms ;wait more that 15ms for display to be ready LOAD s4, 30 CALL LCD_write_inst4 ;send '3' CALL delay_20ms ;wait >4.1ms CALL LCD_write_inst4 ;send '3' CALL delay_1ms ;wait >100us CALL LCD_write_inst4 ;send '3' CALL delay_40us ;wait >40us LOAD s4, 20 CALL LCD_write_inst4 ;send '2' CALL delay_40us ;wait >40us LOAD s5, 28 ;Function set CALL LCD_write_inst8 LOAD s5, 06 ;Entry mode CALL LCD_write_inst8 LOAD s5, 0C ;Display control CALL LCD_write_inst8 LCD_clear: LOAD s5, 01 ;Display clear CALL LCD_write_inst8 CALL delay_1ms ;wait >1.64ms for display to clear CALL delay_1ms RETURN ; ;Position the cursor ready for characters to be written. ;The display is formed of 2 lines of 16 characters and each ;position has a corresponding address as indicated below. ; ; Character position ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; ; Line 1 - 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F ; Line 2 - C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF ; ;This routine will set the cursor position using the value provided ;in register s5. The upper nibble will define the line and the lower ;nibble the character position on the line. ; Example s5 = 2B will position the cursor on line 2 position 11 ; ;Registers used s0, s1, s2, s3, s4 ; LCD_cursor: TEST s5, 10 ;test for line 1 JUMP Z, set_line2 AND s5, 0F ;make address in range 80 to 8F for line 1 OR s5, 80 CALL LCD_write_inst8 ;instruction write to set cursor RETURN set_line2: AND s5, 0F ;make address in range C0 to CF for line 2 OR s5, C0 CALL LCD_write_inst8 ;instruction write to set cursor RETURN ; ; ; ************************************************************** ; Interrupt Service Routine (ISR) ; ************************************************************** ISR: STORE s0, ISR_preserve_s0 ;preserve s0 FETCH s0, ISR_counter ; counter for ISR ADD s0, 01 STORE s0, ISR_counter AND s0, ISR_data OUTPUT s0, LED_port FETCH s0, ISR_preserve_s0 ;restore s0 RETURNI ENABLE ; ; ************************************************************** ; Interrupt Vector ; ************************************************************** ADDRESS 3FF JUMP ISR ; ; ; Useful constants ; ; ASCII table ; CONSTANT CHRASCl_a, 61 CONSTANT CHRASCl_b, 62 CONSTANT CHRASCl_c, 63 CONSTANT CHRASCl_d, 64 CONSTANT CHRASCl_e, 65 CONSTANT CHRASCl_f, 66 CONSTANT CHRASCl_g, 67 CONSTANT CHRASCl_h, 68 CONSTANT CHRASCl_i, 69 CONSTANT CHRASCl_j, 6A CONSTANT CHRASCl_k, 6B CONSTANT CHRASCl_l, 6C CONSTANT CHRASCl_m, 6D CONSTANT CHRASCl_n, 6E CONSTANT CHRASCl_o, 6F CONSTANT CHRASCl_p, 70 CONSTANT CHRASCl_q, 71 CONSTANT CHRASCl_r, 72 CONSTANT CHRASCl_s, 73 CONSTANT CHRASCl_t, 74 CONSTANT CHRASCl_u, 75 CONSTANT CHRASCl_v, 76 CONSTANT CHRASCl_w, 77 CONSTANT CHRASCl_x, 78 CONSTANT CHRASCl_y, 79 CONSTANT CHRASCl_z, 7A CONSTANT CHRASCu_A, 41 CONSTANT CHRASCu_B, 42 CONSTANT CHRASCu_C, 43 CONSTANT CHRASCu_D, 44 CONSTANT CHRASCu_E, 45 CONSTANT CHRASCu_F, 46 CONSTANT CHRASCu_G, 47 CONSTANT CHRASCu_H, 48 CONSTANT CHRASCu_I, 49 CONSTANT CHRASCu_J, 4A CONSTANT CHRASCu_K, 4B CONSTANT CHRASCu_L, 4C CONSTANT CHRASCu_M, 4D CONSTANT CHRASCu_N, 4E CONSTANT CHRASCu_O, 4F CONSTANT CHRASCu_P, 50 CONSTANT CHRASCu_Q, 51 CONSTANT CHRASCu_R, 52 CONSTANT CHRASCu_S, 53 CONSTANT CHRASCu_T, 54 CONSTANT CHRASCu_U, 55 CONSTANT CHRASCu_V, 56 CONSTANT CHRASCu_W, 57 CONSTANT CHRASCu_X, 58 CONSTANT CHRASCu_Y, 59 CONSTANT CHRASCu_Z, 5A CONSTANT CHRASC_0, 30 CONSTANT CHRASC_1, 31 CONSTANT CHRASC_2, 32 CONSTANT CHRASC_3, 33 CONSTANT CHRASC_4, 34 CONSTANT CHRASC_5, 35 CONSTANT CHRASC_6, 36 CONSTANT CHRASC_7, 37 CONSTANT CHRASC_8, 38 CONSTANT CHRASC_9, 39 CONSTANT CHRASC_minus, 2D CONSTANT CHRASC_dot, 2E CONSTANT CHRASC_colon, 3A CONSTANT CHRASC_semi_colon, 3B CONSTANT CHRASC_less_than, 3C CONSTANT CHRASC_greater_than, 3E CONSTANT CHRASC_rbrleft, 5B CONSTANT CHRASC_rbrright, 5D CONSTANT CHRASC_eql, 3D CONSTANT CHRASC_space, 20 CONSTANT CHRASC_CR, 0D ; carriage return CONSTANT CHRASC_question, 3F ; '?' CONSTANT CHRASC_dollar, 24 CONSTANT CHRASC_aster, 2A CONSTANT CHRASC_hash, 23 CONSTANT CHRASC_slash, 2f CONSTANT CHRASC_BS, 08 ; Back Space command character ; End of file