FDD_DEMO.ASMIt's possible that errors have been introduced to this code during the conversion to HTML. To be sure of the correct code you should download the PIC Assembler ZIP file from the homepage. ;********************************************************************** ;* Filename : fdd_demo.asm ;* ;* Used to test and demonstrate the IDC (I2C Disk Drive Controller). ;* ;* Receives commands from the UART and converts them to I2C commands. ;* ;* The results of the commands are converted into hexadecimal strings ;* and sent back out of the serial port. ;* ;* The serial port settings are 9600 8-N-1. ;* ;* NOTE : Two big string tables are used, so any code changes have to ;* take the position of the tables into account. ;* ;* Author : Craig Dunn (craig_d73@hotmail.com) ;* Date Started : 15 April 2004 ;* Tab Setting : 9 ;* Studio : MPLAB 6.1 ;* Clock : 8MHz (clock dependent - I2C speed, RS232 Baudrate) ;* ;* All of the design and code in this module is my own work. No ;* design or code has been borrowed or copied from any source. ;********************************************************************** #include "p16f874.inc" ERRORLEVEL 0, -302 ; Turn off memory bank warnings LIST P=PIC16F874 ;********************************************************************** ;* Defines ;********************************************************************** #define SET_BANK0 BCF STATUS, RP0 #define SET_BANK1 BSF STATUS, RP0 #define EEPROM_W 0xA0 #define EEPROM_R 0xA1 #define RX_BIT 0x01 #define CMD_FAT_ENTRY 0x46 #define CMD_FAT_VALUE 0x47 #define CMD_SECTOR 0x4F #define CMD_DATA 0xF0 #define CMD_STATUS 0x53 #define CMD_DIR_ENTRY 0x88 #define CMD_DIR_VALUE 0x99 #define IDC_R 0x03 #define IDC_W 0x02 #define CR 0x0D #define FF 0x0C #define GP_REF_OFF 0x20 ;********************************************************************** ;* Variables ;********************************************************************** track EQU (GP_REF_OFF + 0x00) side_sector EQU (GP_REF_OFF + 0x01) uart EQU (GP_REF_OFF + 0x02) rx_reg EQU (GP_REF_OFF + 0x03) tx_reg EQU (GP_REF_OFF + 0x04) nibble EQU (GP_REF_OFF + 0x05) hex_temp EQU (GP_REF_OFF + 0x06) i2c_rx_reg EQU (GP_REF_OFF + 0x07) byte_offset EQU (GP_REF_OFF + 0x08) str_id EQU (GP_REF_OFF + 0x09) x_cnt EQU (GP_REF_OFF + 0x0A) hex_reg EQU (GP_REF_OFF + 0x0B) y_cnt EQU (GP_REF_OFF + 0x0C) hex_value EQU (GP_REF_OFF + 0x0D) hex_cnt EQU (GP_REF_OFF + 0x0E) fat_entry_hi EQU (GP_REF_OFF + 0x0F) fat_entry_lo EQU (GP_REF_OFF + 0x10) fat_value_hi EQU (GP_REF_OFF + 0x11) fat_value_lo EQU (GP_REF_OFF + 0x12) dir_entry EQU (GP_REF_OFF + 0x13) tempw EQU (GP_REF_OFF + 0x14) tempst EQU (GP_REF_OFF + 0x15) ;********************************************************************** ;* MACRO's ;* ;* MOVLF - Move a literal to a file ;* MOVFF - Move a file to a file ;* SUBLF - Subtract a literal from a file ;* ADDLF - Add a literal to a file ;* DCFSNZ - Decrement File Skip if Not Zero ;* ADDFF - Add file to file ;********************************************************************** MOVLF MACRO literal, file MOVLW literal MOVWF file ENDM MOVFF MACRO file_a, file_b MOVFW file_a MOVWF file_b ENDM SUBLF MACRO literal, file MOVLW literal SUBWF file, F ENDM ADDLF MACRO literal, file MOVFW file ADDLW literal MOVWF file ENDM DCFSNZ MACRO file DECFSZ file, F GOTO $+3 ; Not zero GOTO $+1 ; Zero ENDM ADDFF MACRO file_a, file_b MOVFW file_a ADDWF file_b, F ENDM ;********************************************************************** ;* Vector table ;********************************************************************** ORG 0x00 GOTO init ORG 0x04 GOTO int_srv ;********************************************************************** ;* Main implementation. ;********************************************************************** init: ; Setup the ports ;------------------------------------------------------------------ SET_BANK1 CLRF TRISB ; Set PORTB as an output (LED's) MOVLF 0xFF, TRISC ; Set PORTC as an input (I2C, UART) SET_BANK0 ; Setup the I2C ;------------------------------------------------------------------ SET_BANK0 MOVLF 0x38, SSPCON ; Enable I2C Master mode SET_BANK1 MOVLF 0x00, SSPSTAT MOVLF 0x04, SSPADD ; 400KHz I2C SET_BANK0 ; Setup the UART ;------------------------------------------------------------------ SET_BANK1 MOVLF 0x33, SPBRG ; 9600 baud rate BSF TXSTA, BRGH ; High speed mode BSF TXSTA, TXEN ; Enable transmit SET_BANK0 BSF RCSTA, SPEN ; Enable the serial port BSF RCSTA, CREN ; Continuous receive SET_BANK1 BSF PIE1, RCIE ; Enable receive interrupt SET_BANK0 BSF INTCON, PEIE ; Enable unmasked peripheral interrupts BSF INTCON, GIE ; Enable interrupts ; Main implementation ;------------------------------------------------------------------ main: MOVLF 0x00, track MOVLF 0x81, side_sector MOVLF 0x00, dir_entry MOVLF 0x00, fat_entry_hi MOVLF 0x00, fat_entry_lo MOVLF 0x00, fat_value_hi MOVLF 0x00, fat_value_lo refresh: ; Display the menu ;------------------------------------------------------------------ MOVLF FF, tx_reg CALL uart_tx ; Clear the display (Form Feed) MOVLF (menu_str - str_table_start), str_id CALL uart_tx_str MOVLF (current_track_str - str_table_start2), str_id CALL uart_tx_str2 MOVFF track, tx_reg CALL uart_tx_hex MOVLF (current_sector_str - str_table_start2), str_id CALL uart_tx_str2 MOVFF side_sector, tx_reg CALL uart_tx_hex ; Wait here until the user makes a menu choice ;------------------------------------------------------------------ wait_cmd: BCF uart, RX_BIT ; Allows us to receive a byte wait_new_cmd: BTFSC uart, RX_BIT GOTO process_cmd GOTO wait_new_cmd ; Menu choice case statement ;------------------------------------------------------------------ process_cmd: MOVFW rx_reg XORLW '0' BTFSC STATUS, Z GOTO refresh ; Refresh the menu MOVFW rx_reg XORLW '1' BTFSC STATUS, Z GOTO cmd_read_sector ; Read a sector MOVFW rx_reg XORLW '2' BTFSC STATUS, Z GOTO cmd_write_sector ; Write a sector MOVFW rx_reg XORLW '3' BTFSC STATUS, Z GOTO cmd_read_data ; Read data from the controller MOVFW rx_reg XORLW '4' BTFSC STATUS, Z GOTO cmd_write_data ; Write data to the controller MOVFW rx_reg XORLW '5' BTFSC STATUS, Z GOTO cmd_read_fat_entry ; Read a FAT entry MOVFW rx_reg XORLW '6' BTFSC STATUS, Z GOTO cmd_read_fat_value ; Read a FAT value MOVFW rx_reg XORLW '7' BTFSC STATUS, Z GOTO cmd_write_fat_entry ; Write a FAT entry MOVFW rx_reg XORLW '8' BTFSC STATUS, Z GOTO cmd_write_fat_value ; Write a FAT value MOVFW rx_reg XORLW 'A' BTFSC STATUS, Z GOTO cmd_read_dir_entry ; Read a directory entry MOVFW rx_reg XORLW 'B' BTFSC STATUS, Z GOTO cmd_write_dir_entry ; Write a directory entry MOVFW rx_reg XORLW 'C' BTFSC STATUS, Z GOTO cmd_read_dir_value ; Read a directory value MOVFW rx_reg XORLW 'D' BTFSC STATUS, Z GOTO cmd_write_dir_value ; Write a directory value MOVFW rx_reg XORLW '9' BTFSC STATUS, Z GOTO cmd_status ; Read the status MOVFW rx_reg XORLW 'T' BTFSC STATUS, Z GOTO cmd_track ; Set the track MOVFW rx_reg XORLW 'S' BTFSC STATUS, Z GOTO cmd_sector ; Set the side / sector GOTO wait_cmd ; Read a directory entry ;------------------------------------------------------------------ cmd_read_dir_entry: MOVLF (dir_entry_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, dir_entry CALL idc_read_dir_entry GOTO wait_cmd ; Write a directory entry ;------------------------------------------------------------------ cmd_write_dir_entry: CALL idc_write_dir_entry GOTO wait_cmd ; Read a directory value ;------------------------------------------------------------------ cmd_read_dir_value: CALL idc_read_dir_value GOTO wait_cmd ; Write a directory value ;------------------------------------------------------------------ cmd_write_dir_value: MOVLF (value_str - str_table_start2), str_id CALL uart_tx_str2 CALL idc_write_dir_value GOTO wait_cmd ; Read a sector ;------------------------------------------------------------------ cmd_read_sector: CALL idc_read_sector GOTO wait_cmd ; Write a sector ;------------------------------------------------------------------ cmd_write_sector: CALL idc_write_sector GOTO wait_cmd ; Read data ;------------------------------------------------------------------ cmd_read_data: CALL idc_read_data GOTO wait_cmd ; Write data ;------------------------------------------------------------------ cmd_write_data: MOVLF (value_str - str_table_start2), str_id CALL uart_tx_str2 CALL idc_write_data GOTO wait_cmd ; Read FAT entry ;------------------------------------------------------------------ cmd_read_fat_entry: MOVLF (fat_entry_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, fat_entry_hi CALL uart_rx_hex MOVFF hex_value, fat_entry_lo CALL idc_read_fat_entry GOTO wait_cmd ; Read FAT value ;------------------------------------------------------------------ cmd_read_fat_value: MOVLF (fat_value_str - str_table_start2), str_id CALL uart_tx_str2 CALL idc_read_fat_value MOVFF fat_value_hi, tx_reg CALL uart_tx_hex MOVFF fat_value_lo, tx_reg CALL uart_tx_hex GOTO wait_cmd ; Write FAT entry ;------------------------------------------------------------------ cmd_write_fat_entry: MOVLF (fat_entry_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, fat_entry_hi CALL uart_rx_hex MOVFF hex_value, fat_entry_lo CALL idc_write_fat_entry GOTO wait_cmd ; Write FAT value ;------------------------------------------------------------------ cmd_write_fat_value: MOVLF (fat_value_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, fat_value_hi CALL uart_rx_hex MOVFF hex_value, fat_value_lo CALL idc_write_fat_value GOTO wait_cmd ; Status ;------------------------------------------------------------------ cmd_status: MOVLF (status_str - str_table_start2), str_id CALL uart_tx_str2 CALL idc_read_status MOVWF tx_reg CALL uart_tx_hex GOTO wait_cmd ; Track ;------------------------------------------------------------------ cmd_track: MOVLF (track_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, track GOTO refresh ; Sector ;------------------------------------------------------------------ cmd_sector: MOVLF (sector_str - str_table_start2), str_id CALL uart_tx_str2 CALL uart_rx_hex MOVFF hex_value, side_sector GOTO refresh ;********************************************************************** ;* Generate an I2C START condition. ;********************************************************************** i2c_start: BCF PIR1, SSPIF ; Clear the completed flag SET_BANK1 BSF SSPCON2, SEN ; Generate a START SET_BANK0 BTFSS PIR1, SSPIF ; Wait until the START is complete GOTO $-1 RETURN ;********************************************************************** ;* Generate an I2C STOP condition. ;********************************************************************** i2c_stop: BCF PIR1, SSPIF ; Clear the completed flag SET_BANK1 BSF SSPCON2, PEN ; Generate a STOP SET_BANK0 BTFSS PIR1, SSPIF ; Wait until the STOP is complete GOTO $-1 RETURN ;********************************************************************** ;* Send the byte in W out on the I2C bus. Doesn't return until the ;* the transmission is complete. ;********************************************************************** i2c_send: BCF PIR1, SSPIF ; Clear the completed flag MOVWF SSPBUF ; Send the byte BTFSS PIR1, SSPIF ; Wait here until the byte is sent GOTO $-1 RETURN ;********************************************************************** ;* Receive a byte from the I2C bus and put it in i2c_rx_reg. ;********************************************************************** i2c_recv: BCF PIR1, SSPIF ; Clear the completed flag SET_BANK1 BSF SSPCON2, RCEN ; Receive the byte SET_BANK0 BTFSS PIR1, SSPIF ; Wait here until the byte is received GOTO $-1 MOVFF SSPBUF, i2c_rx_reg ; Put the received byte in i2c_rx_reg RETURN ;********************************************************************** ;* Send an ACK out on the I2C bus. ;********************************************************************** i2c_ack: BCF PIR1, SSPIF ; Clear the completed flag SET_BANK1 BCF SSPCON2, ACKDT BSF SSPCON2, ACKEN SET_BANK0 BTFSS PIR1, SSPIF ; Wait here until the ACK is received GOTO $-1 RETURN ;********************************************************************** ;* Send a NACK out on the I2C bus. ;********************************************************************** i2c_nack: BCF PIR1, SSPIF ; Clear the completed flag SET_BANK1 BSF SSPCON2, ACKDT BSF SSPCON2, ACKEN SET_BANK0 BTFSS PIR1, SSPIF ; Wait here until the ACK is received GOTO $-1 RETURN ;********************************************************************** ;* Read the status from the IFC. ;********************************************************************** idc_read_status: CALL i2c_stop CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_status_nack SET_BANK0 MOVLW CMD_STATUS CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_status_nack SET_BANK0 CALL i2c_recv ; Receive the status CALL i2c_nack ; Send a NACK idc_read_status_nack: SET_BANK0 CALL i2c_stop ; STOP RETURN ;********************************************************************** ;* Write a new FAT entry to the IDC. ;********************************************************************** idc_write_fat_entry: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_entry_nack SET_BANK0 MOVLW CMD_FAT_ENTRY CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_entry_nack SET_BANK0 MOVFW fat_entry_hi CALL i2c_send ; High entry SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_entry_nack SET_BANK0 MOVFW fat_entry_lo CALL i2c_send ; Low entry SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_entry_nack SET_BANK0 idc_wr_fat_entry_nack: SET_BANK0 CALL i2c_stop ; STOP RETURN ;********************************************************************** ;* Write a new value to the current directory entry. ;********************************************************************** idc_write_dir_value: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_dir_value_nack SET_BANK0 MOVLW CMD_DIR_VALUE CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_dir_value_nack SET_BANK0 ; Keep reading in bytes until the CR is detected next_dir_byte: BCF uart, RX_BIT BTFSS uart, RX_BIT GOTO $-1 MOVFF rx_reg, tx_reg CALL uart_tx MOVFW rx_reg XORLW CR BTFSC STATUS, Z GOTO write_dir_finished MOVFW rx_reg CALL i2c_send SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_dir_value_nack SET_BANK0 GOTO next_dir_byte write_dir_finished: idc_wr_dir_value_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Write a new FAT value to the IDC (hi_value, lo_value). ;********************************************************************** idc_write_fat_value: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_value_nack SET_BANK0 MOVLW CMD_FAT_VALUE CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_value_nack SET_BANK0 MOVFW fat_value_hi CALL i2c_send ; High value SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_value_nack SET_BANK0 MOVFW fat_value_lo CALL i2c_send ; Low value SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_fat_value_nack SET_BANK0 idc_wr_fat_value_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Read the FAT value from the IDC. ;********************************************************************** idc_read_fat_value: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_value_nack SET_BANK0 MOVLW CMD_FAT_VALUE CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_value_nack SET_BANK0 CALL i2c_recv ; Receive the hi value CALL i2c_ack ; Send an ACK MOVFF i2c_rx_reg, fat_value_hi CALL i2c_recv ; Receive the lo value CALL i2c_nack ; Send an NACK MOVFF i2c_rx_reg, fat_value_lo idc_read_fat_value_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Instruct the IDC to read a directory entry. ;********************************************************************** idc_read_dir_entry: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_rd_dir_entry_nack SET_BANK0 MOVLW CMD_DIR_ENTRY CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_rd_dir_entry_nack SET_BANK0 MOVFW dir_entry CALL i2c_send ; Entry SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_rd_dir_entry_nack SET_BANK0 idc_rd_dir_entry_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Instruct the IDC to write the current directory entry. ;********************************************************************** idc_write_dir_entry: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_dir_entry_nack SET_BANK0 MOVLW CMD_DIR_ENTRY CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_wr_dir_entry_nack SET_BANK0 idc_wr_dir_entry_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Instruct the IDC to read a sector (track, side_sector). ;********************************************************************** idc_read_sector: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_sector_nack SET_BANK0 MOVLW CMD_SECTOR CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_sector_nack SET_BANK0 MOVFW track CALL i2c_send ; Track SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_sector_nack SET_BANK0 MOVFW side_sector CALL i2c_send ; Side / Sector SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_sector_nack SET_BANK0 idc_read_sector_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Instruct the IDC to write a sector (track, side_sector). ;********************************************************************** idc_write_sector: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_sector_nack SET_BANK0 MOVLW CMD_SECTOR CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_sector_nack SET_BANK0 MOVFW track CALL i2c_send ; Track SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_sector_nack SET_BANK0 MOVFW side_sector CALL i2c_send ; Side / Sector SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_sector_nack SET_BANK0 idc_write_sector_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Read the contents of the IDC's RAM, which contains a sector and ;* display the results as hex strings. ;********************************************************************** idc_read_data: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_data_nack SET_BANK0 MOVLW CMD_DATA CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_data_nack SET_BANK0 MOVLF CR, tx_reg ; Start the display on a new line CALL uart_tx MOVLF 0x21, y_cnt ; 32 lines of 16 bytes data_new_line: MOVLF 0x10, x_cnt ; 16 bytes per line DCFSNZ y_cnt GOTO data_finish data_next_byte: CALL i2c_recv ; Get the byte from the I2C bus CALL i2c_ack MOVFF i2c_rx_reg, tx_reg CALL uart_tx_hex ; Display the byte as a hex string MOVLF ' ', tx_reg ; Put a space between the hex strings DCFSNZ x_cnt MOVLF CR, tx_reg ; End each line with a carriage return CALL uart_tx MOVFW x_cnt ADDLW 0x00 BTFSC STATUS, Z ; If the end of the line then start a new line GOTO data_new_line GOTO data_next_byte data_finish: ; All receiving operations from the slave end in a ; NACK. Putting it here makes the above loop simpler. CALL i2c_recv CALL i2c_nack idc_read_data_nack: SET_BANK0 CALL i2c_stop ; STOP RETURN ;********************************************************************** ;* Write data to the IDC. ;********************************************************************** idc_write_data: CALL i2c_start ; START MOVLW IDC_W CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_data_nack SET_BANK0 MOVLW CMD_DATA CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_data_nack SET_BANK0 ; Keep reading in bytes until the CR is detected next_data_byte: BCF uart, RX_BIT BTFSS uart, RX_BIT GOTO $-1 MOVFF rx_reg, tx_reg CALL uart_tx MOVFW rx_reg XORLW CR BTFSC STATUS, Z GOTO write_data_finished MOVFW rx_reg CALL i2c_send SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_write_data_nack SET_BANK0 GOTO next_data_byte write_data_finished idc_write_data_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Instruct the IDC to read a FAT entry. ;********************************************************************** idc_read_fat_entry: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_entry_nack SET_BANK0 MOVLW CMD_FAT_ENTRY CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_entry_nack SET_BANK0 MOVFW fat_entry_hi CALL i2c_send ; FAT high entry SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_entry_nack SET_BANK0 MOVFW fat_entry_lo CALL i2c_send ; FAT low entry SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_read_fat_entry_nack SET_BANK0 idc_read_fat_entry_nack: SET_BANK0 CALL i2c_stop RETURN ;********************************************************************** ;* Read a 32 byte directory entry from the IDC and display the ;* results as hex strings. ;********************************************************************** idc_read_dir_value: CALL i2c_start ; START MOVLW IDC_R CALL i2c_send ; Control byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_rd_dir_value_nack SET_BANK0 MOVLW CMD_DIR_VALUE CALL i2c_send ; Command byte SET_BANK1 BTFSC SSPCON2, ACKSTAT ; Check for ACK GOTO idc_rd_dir_value_nack SET_BANK0 MOVLF CR, tx_reg CALL uart_tx ; Start a new line before display the Dir MOVLF 0x03, y_cnt ; Two lines of 16 bytes dir_new_line: MOVLF 0x10, x_cnt ; Sixteen bytes per line DCFSNZ y_cnt GOTO dir_finish ; Displayed the whole directory dir_next_byte: CALL i2c_recv ; Get the byte from the I2C bus CALL i2c_ack MOVFF i2c_rx_reg, tx_reg CALL uart_tx_hex ; Display the byte as a hex string MOVLF ' ', tx_reg ; Put a space between the bytes DCFSNZ x_cnt MOVLF CR, tx_reg ; Put a CR at the end of each line CALL uart_tx MOVFW x_cnt ADDLW 0x00 BTFSC STATUS, Z ; If x_cnt is start a new line GOTO dir_new_line GOTO dir_next_byte dir_finish: ; All receiving operations from the slave end in a ; NACK. Putting it here makes the above loop simpler. CALL i2c_recv CALL i2c_nack idc_rd_dir_value_nack: SET_BANK0 CALL i2c_stop ; STOP RETURN ;********************************************************************** ;* Interrupt service routine. ;* ;* If a byte has been received by the UART and uart, RX_BIT is clear ;* put the byte in rx_reg. ;********************************************************************** int_srv: MOVWF tempw ; Store W and STATUS SWAPF STATUS, W SET_BANK0 MOVWF tempst BTFSS PIR1, RCIF ; Check the interrupt is from the UART GOTO int_srv_ret BTFSC uart, RX_BIT ; If RX_BIT is set then rx_reg GOTO int_srv_ret ; hasn't been processed yet MOVFF RCREG, rx_reg ; Store the received byte BSF uart, RX_BIT ; Signal a new byte has arrived MOVFW RCREG ; There could be a second byte BCF RCSTA, CREN BSF RCSTA, CREN int_srv_ret: MOVFW RCREG ; There could be a second byte MOVFW RCREG ; There could be a second byte SWAPF tempst, W ; Restore W and STATUS MOVWF STATUS SWAPF tempw, F SWAPF tempw, W RETFIE ;********************************************************************** ;* Send whatever is in tx_reg out of the serial port. ;********************************************************************** uart_tx: BTFSS PIR1, TXIF ; Wait for the serial port to become free GOTO $-1 MOVFF tx_reg, TXREG ; Send the byte RETURN ;********************************************************************** ;* Convert the value in tx_reg to a 2 byte ASCII hex string and send ;* it out of the UART. ;********************************************************************** uart_tx_hex: MOVFW tx_reg MOVWF hex_temp ANDLW 0xF0 MOVWF hex_reg SWAPF hex_reg, F CALL to_hex MOVWF tx_reg CALL uart_tx ; Top nibble MOVFW hex_temp ANDLW 0x0F MOVWF hex_reg CALL to_hex MOVWF tx_reg CALL uart_tx ; Bottom nibble RETURN ;********************************************************************** ;* Convert the lower nibble of hex_reg to it's hex ASCII Equivalent. ;* The result is in W. ;********************************************************************** to_hex: INCF hex_reg, F MOVLW LOW hex_table ADDWF hex_reg, F MOVLW HIGH hex_table BTFSC STATUS, C ADDLW 0x01 MOVWF PCLATH MOVFW hex_reg CALL hex_table RETURN ;********************************************************************** ;* The to_hex lookup table. ;********************************************************************** hex_table: MOVWF PCL RETLW '0' RETLW '1' RETLW '2' RETLW '3' RETLW '4' RETLW '5' RETLW '6' RETLW '7' RETLW '8' RETLW '9' RETLW 'A' RETLW 'B' RETLW 'C' RETLW 'D' RETLW 'E' RETLW 'F' ;********************************************************************** ;* Transmit tx_reg as a hex string. ;********************************************************************** uart_rx_hex: BCF hex_cnt, 0 wait_rx_byte: BCF uart, RX_BIT ; Allows us to receive a byte BTFSS uart, RX_BIT ; wait for a byte from the UART GOTO $-1 MOVFF rx_reg, tx_reg CALL uart_tx MOVFF rx_reg, hex_temp MOVLW 'A' SUBWF hex_temp, F BTFSC STATUS, C GOTO alpha ; Numeric SUBLF '0', rx_reg GOTO continue alpha: SUBLF 'A', rx_reg ADDLF 0x0A, rx_reg continue: BTFSC hex_cnt, 0 GOTO finished BSF hex_cnt, 0 MOVFF rx_reg, hex_value SWAPF hex_value, F GOTO wait_rx_byte finished: ADDFF rx_reg, hex_value RETURN ;********************************************************************** ;* Transmit the string identified by str_id out of the UART. ;********************************************************************** uart_tx_str: INCF str_id, F next_byte: MOVFF str_id, byte_offset CALL get_str_byte ADDLW 0x00 BTFSC STATUS, Z GOTO uart_tx_str_ret MOVWF tx_reg CALL uart_tx INCF str_id, F GOTO next_byte uart_tx_str_ret: RETURN ;********************************************************************** ;* Transmit a string from thex second string table. ;********************************************************************** uart_tx_str2: INCF str_id, F next_byte2: MOVFF str_id, byte_offset CALL get_str_byte2 ADDLW 0x00 BTFSC STATUS, Z GOTO uart_tx_str_ret2 MOVWF tx_reg CALL uart_tx INCF str_id, F GOTO next_byte2 uart_tx_str_ret2: RETURN ;********************************************************************** ;* Read a byte from the string table. The byte is identified by ;* byte_offset. ;********************************************************************** ORG 0x400 get_str_byte: MOVLW LOW str_table ADDWF byte_offset, F MOVLW HIGH str_table BTFSC STATUS, C ADDLW 0x01 MOVWF PCLATH MOVFW byte_offset CALL str_table RETURN ;********************************************************************** ;* The string table. Used by uart_tx_str. ;********************************************************************** str_table: MOVWF PCL str_table_start: menu_str: DT "IDC Menu", CR, CR DT "1. RD sector", CR DT "2. WR sector", CR DT "3. RD data", CR DT "4. WR data", CR DT "5. RD FAT Entry", CR DT "6. RD FAT Value", CR DT "7. WR FAT Entry", CR DT "8. WR FAT Value", CR DT "A. RD Dir Entry", CR DT "B. WR Dir Entry", CR DT "C. RD Dir Value", CR DT "D. WR Dir Value", CR DT "9. Status", CR DT "T. Track", CR DT "S. Side / Sector", CR DT "0. Refresh", CR, CR, 0x00 ;********************************************************************** ;* Get a byte from the second string table. ;********************************************************************** ORG 0x500 get_str_byte2: MOVLW LOW str_table2 ADDWF byte_offset, F MOVLW HIGH str_table2 BTFSC STATUS, C ADDLW 0x01 MOVWF PCLATH MOVFW byte_offset CALL str_table RETURN ;********************************************************************** ;* The string table. Used by uart_tx_str2. ;********************************************************************** str_table2: MOVWF PCL str_table_start2: status_str: DT CR, "STATUS : 0x", 0x00 track_str: DT CR, "New Track : 0x", 0x00 sector_str: DT CR, "New Side / Sector : 0x", 0x00 fat_entry_str: DT CR, "FAT Entry : 0x", 0x00 fat_value_str: DT CR, "FAT Value : 0x", 0x00 dir_entry_str: DT CR, "DIR Entry : 0x", 0x00 current_track_str: DT "Track : 0x", 0x00 current_sector_str: DT CR, "Side / Sector : 0x", 0x00 value_str: DT CR, "Value : ", 0x00 END
|