|
|
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
|