'************************************************************************************************************************ ' 0.1 to 40 Hz ELF Recorder ' File name : recorder-1.pbp ' Date : 2011-11 ' Author : Serge Lacôte ' Langage : PICBASIC PRO 2.6 ; LONG option enabled ' Assembler : MPASM v5.42 ' MCU target : PIC18LF4620 ' ADC : Analog Device AD7680 (16 bit) ' RTC : Maxim DS1302 ' Serial interface : Maxim MAX3232 ' Medium : SD card (2Go) ; the card must be initialized in plain FAT16 (16bit version FAT) WITHOUT PARTITION before using ' with following parameters : sector size : 512 Bytes, cluster size : 64 sectors i.e. 32 kB. ' Supply voltage : 3.3 V ' File system : FAT16 ' Prescaler TIMER0 : none ; stop counter : 37523 - T0CON = % x0001000 ' If Prescaler 1:4 stop counter : 9445 - T0CON = % x0000001 *** If 1:8 stop counter : 4723 - T0CON = %x0000010 ' Sample rate : 128 sps ' This program may be freely used, copied and modified for a private using '************************************************************************************************************************ '************************************************************************************************************************ DEFINE OSC 20 ' The crystal frequency is 20 MHz ; the instruction frequency is 5 MHz ' PIC18LF4620 ports and direction registers ' NOTA. IN SPI mode, the names IN, OUT, CS, etc. refer to the uC (master), not to the slave chip. SD_CS Var PORTC.1 SD_CS_TRIS Var TRISC.1 SCL Var PORTC.3 SCL_TRIS Var TRISC.3 SDO Var PORTC.5 SDO_TRIS Var TRISC.5 SDI Var PORTC.4 SDI_TRIS Var TRISC.4 ADC_CS Var PORTD.2 ADC_CS_TRIS Var TRISD.2 ADC_SDATA Var PORTD.3 ADC_SDATA_TRIS Var TRISD.3 ADC_SCLK Var PORTD.4 ADC_SCLK_TRIS Var TRISD.4 START_BUT Var PORTB.0 START_BUT_TRIS Var TRISB.0 LED_RED Var PORTD.1 LED_RED_TRIS Var TRISD.1 LED_GREEN Var PORTD.0 LED_GREEN_TRIS Var TRISD.0 CLOSE_BUTTON Var PORTB.2 CLOSE_BUTTON_TRIS Var TRISB.2 SETTING_BUT Var PORTB.1 SETTING_BUT_TRIS Var TRISB.1 RTC_IO Var PORTE.1 RTC_IO_TRIS Var TRISE.1 RTC_CLK Var PORTE.0 RTC_CLK_TRIS Var TRISE.0 RTC_CE Var PORTE.2 RTC_CE_TRIS Var TRISE.2 CUT_OFF_BATT Var PORTD.5 CUT_OFF_BATT_TRIS Var TRISD.5 ' Various variables YEAR Var Byte ' BDC coded DS1302 year (00-99) MONTH Var Byte ' BDC coded DS1302 month (1-12) DATE Var Byte ' BDC coded DS1302 date (1-31) HOUR Var Byte ' BDC coded DS1302 hour (0-23) MINUTE Var Byte ' BDC coded DS1302 minute (00-59) SECOND Var Byte ' BDC coded DS1302 second (00-59) DAY Var Byte ' Non implemented in FAT16 RTC_CTRL Var Byte ' ds1302 control SAMPLE Var Word BIT_COUNTER Var Byte VALUE_TO_SHIFT Var Byte TYPE_1_CARD_REPLY Var Byte ' 8 bits reply TYPE_2_CARD_REPLY Var Word ' 16 bits reply CARD_ADRESS_HIGH Var Word ' Bits 16 to 31 CARD_ADRESS_LOW Var Word ' Bits 0 to 15 SAMPLE_CNTR Var Byte ' Counter I Var Word ' Counter J Var Word ' Counter K Var Word ' Counter L Var Word ' Counter M Var Byte ' Counter N Var Byte ' Counter CHOICE Var Byte CARD_REPLY_4BIT Var Byte BYTES_PER_SECTOR Var Word SECTORS_PER_CLUSTER Var Byte RESERVED_SECTORS Var Word FAT_EXEMPLARS_NBR Var Byte ROOT_ENTRIES_NBR Var Word SECTORS_PER_FAT Var Word DATA_SECTOR_ADRESS_LOW Var Word DATA_SECTOR_ADRESS_HIGH Var Word FAT_SECTOR_ADRESS_LOW Var Word FAT_SECTOR_ADRESS_HIGH Var Word ROOT_SECTOR_ADRESS_LOW Var Word ROOT_SECTOR_ADRESS_HIGH Var Word CLUSTER_CNTR Var Word SECTOR_CNTR Var Byte FILE_LENGTH_HIGH Var Word ' High Word File length FILE_LENGTH_LOW Var Word ' Low Word File length FAT_HOUR Var Word FAT_MINUTE Var Word FAT_SECOND Var Word FAT_YEAR Var Word FAT_MONTH Var Word FAT_DATE Var Word FAT_HMS Var Word ' Hours, minutes and second coded on 2 bytes according to FAT16 specifications FAT_YMD Var Word ' Year, month and date coded on 2 bytes according to FAT16 specifications RECORDING_TIME Var Word ' Recording time in hours. RECORDING_TIME_CLUST Var Word ' Recording time in number of clusters. FILE_NAME Var Byte[8] '************************************************************************************************************************ ' Various register initialization INTCON = %00000000 ' Interrupts disabled INTCON2 = %00000000 ' Pullups on PORTB enabled INTCON3 = %00000000 ' External interrupts disabled ADCON1 = %00001111 ' I/O for all ports T0CON = %00001000 ' TIMER0 disabled ; no prescaler '************************************************************************************************************************ ' Direction registers START_BUT_TRIS = 1 SETTING_BUT_TRIS = 1 SD_CS_TRIS = 0 SCL_TRIS = 0 SDO_TRIS = 0 SDI_TRIS = 1 ADC_CS_TRIS = 0 ADC_SDATA_TRIS = 1 ADC_SCLK_TRIS = 0 LED_RED_TRIS = 0 LED_GREEN_TRIS = 0 CLOSE_BUTTON_TRIS = 1 RTC_CLK_TRIS = 0 RTC_CE_TRIS = 0 CUT_OFF_BATT_TRIS = 0 '************************************************************************************************************************ Pause 1000 CUT_OFF_BATT = 0 ' Waiting loop for settings Pause 1000 If SETTING_BUT == 0 Then Gosub SETTINGS EndIf ' Start waiting loop M = 0 While 1 ' Waiting loop button START_BUT, 0, 0, 0, M, 1, MAIN Wend '************************************************ MAIN ****************************************************************** MAIN : Pause 1000 LED_RED = 0 LED_GREEN = 0 Pause 1000 GoSub SD_INIT GoSub READ_BOOT_SECTOR ' FAT sector I = RESERVED_SECTORS GoSub CARD_ADDRESS_CALCULATION FAT_SECTOR_ADRESS_LOW = CARD_ADRESS_LOW FAT_SECTOR_ADRESS_HIGH = CARD_ADRESS_HIGH ' ROOT sector I = I + SECTORS_PER_FAT * FAT_EXEMPLARS_NBR GoSub CARD_ADDRESS_CALCULATION ROOT_SECTOR_ADRESS_LOW = CARD_ADRESS_LOW ROOT_SECTOR_ADRESS_HIGH = CARD_ADRESS_HIGH ' Data sector I = I + (ROOT_ENTRIES_NBR / 512) * 32 GoSub CARD_ADDRESS_CALCULATION DATA_SECTOR_ADRESS_LOW = CARD_ADRESS_LOW DATA_SECTOR_ADRESS_HIGH = CARD_ADRESS_HIGH CLUSTER_CNTR = 0 SECTOR_CNTR = 0 CARD_ADRESS_LOW = DATA_SECTOR_ADRESS_LOW CARD_ADRESS_HIGH = DATA_SECTOR_ADRESS_HIGH FILE_LENGTH_LOW = 0 FILE_LENGTH_HIGH = 0 LED_GREEN = 1 SAMPLE_CNTR = 0 READ 0, Word RECORDING_TIME RECORDING_TIME_CLUST = RECORDING_TIME */ 7200 'Serout2 PORTC.6, 84, ["recording cluster numbers = ", DEC RECORDING_TIME_CLUST, 13] GoSub READ_TIME ' Creation date (beginning of the recording) GoSub WRITE_INIT While (CLOSE_BUTTON == 1) && (CLUSTER_CNTR < RECORDING_TIME_CLUST) For SAMPLE_CNTR = 0 to 254 GoSub DIGITIZE VALUE_TO_SHIFT = SAMPLE.byte0 GoSub FAST_SHIFTOUT ' Writing on the card VALUE_TO_SHIFT = SAMPLE.byte1 GoSub FAST_SHIFTOUT ' Writing on the card TMR0L = 0 TMR0H = 0 T0CON.7 = 1 ' TMR0 enabled ; counting trigged While TMR0L + 256 * TMR0H < 37523 Wend T0CON.7 = 0 ' TMR0 disabled TMR0L = 0 TMR0H = 0 Next SAMPLE_CNTR ' 256th sample (#255), write end and write init for the new sector (if it is) GoSub DIGITIZE VALUE_TO_SHIFT = SAMPLE.byte0 GoSub FAST_SHIFTOUT ' Writing on the card VALUE_TO_SHIFT = SAMPLE.byte1 GoSub FAST_SHIFTOUT ' Writing on the card TMR0L = 0 TMR0H = 0 T0CON.7 = 1 ' TMR0 enabled ; counting trigged GoSub WRITE_END SECTOR_CNTR = SECTOR_CNTR + 1 If SECTOR_CNTR = SECTORS_PER_CLUSTER Then CLUSTER_CNTR = CLUSTER_CNTR + 1 SECTOR_CNTR = 0 EndIf CARD_ADRESS_LOW = CARD_ADRESS_LOW + $0200 If CARD_ADRESS_LOW = $0000 Then CARD_ADRESS_HIGH = CARD_ADRESS_HIGH + 1 EndIf FILE_LENGTH_LOW = FILE_LENGTH_LOW + 512 If FILE_LENGTH_LOW = 0 Then FILE_LENGTH_HIGH = FILE_LENGTH_HIGH + 1 EndIf If (CLOSE_BUTTON == 1) && (CLUSTER_CNTR < RECORDING_TIME_CLUST) Then GoSub WRITE_INIT EndIf While TMR0L + 256 * TMR0H < 37523 Wend T0CON.7 = 0 ' TMR0 disabled TMR0L = 0 TMR0H = 0 Wend GoSub CLOSE_FILE FINISHED : LED_GREEN = 0 Pause 5000 CUT_OFF_BATT = 1 End '************************************************************************************************************************ ' SUBROUTINES '************************************************************************************************************************ '************************************************************************************************************************ SETTINGS : Pause 100 Serout2 PORTC.6, 84, [0, 0, 0, 0, 0, "Setting procedure", 13] Serout2 PORTC.6, 84, 10, ["A : Time setting", 13, "B : Display time", 13, "C : Recording time", 13, "D : Close", 13, "Choice : ", 13] Serout2 PORTC.6, 84, [" !!! Send the choice as a STRING ", 13] Serin2 PORTC.7, 84, [CHOICE] Serout2 PORTC.6, 84, [13] Select Case CHOICE Case "A" Serout2 PORTC.6, 84, ["Set time procedure", 13] Serout2 PORTC.6, 84, [" !!! Write the answers in ordinary DEC, but send them as HEX !!! ", 13] Serout2 PORTC.6, 84, [" !!! Time is UTC, not local time !!! ", 13] Serout2 PORTC.6, 84, 10, ["Day (1-7) : "] Serin2 PORTC.7, 84, [DAY] Serout2 PORTC.6, 84, 10, [13, "Year (00-99) : "] Serin2 PORTC.7, 84, [YEAR] Serout2 PORTC.6, 84, 10,[13, "Month (1-12) : "] Serin2 PORTC.7, 84, [MONTH] Serout2 PORTC.6, 84, 10,[13, "Date (1-31) : "] Serin2 PORTC.7, 84, [DATE] Serout2 PORTC.6, 84, 10,[13, "Hour (0-23) : "] Serin2 PORTC.7, 84, [HOUR] Serout2 PORTC.6, 84, 10,[13, "Minutes (00-59) : "] Serin2 PORTC.7, 84, [MINUTE] Serout2 PORTC.6, 84, 10,[13, "Seconds (00-59) : "] Serin2 PORTC.7, 84, [SECOND] Serout2 PORTC.6, 84, [13, 10] High RTC_CE ' Transfer enable RTC_IO_TRIS = 0 Shiftout RTC_IO, RTC_CLK, 0, [$8E, 0] ' DS1302 write bit enable Low RTC_CE ' Transfer disable High RTC_CE ' Transfer enable Shiftout RTC_IO, RTC_CLK, 0, [$BE, SECOND, MINUTE, HOUR, DATE, MONTH, DAY, YEAR, 0] Low RTC_CE GoTo SETTINGS Case "B" Serout2 PORTC.6, 84, ["Format : #day (1=Sunday) * year-month-date ; hour:minute:second", 13] Gosub READ_TIME Serout2 PORTC.6, 84, [HEX DAY, " * ", HEX YEAR, "-", HEX MONTH, "-", HEX DATE, " ; ", HEX HOUR, ":", HEX MINUTE, ":", HEX SECOND, 13] ' Display DS1302 time GoTo SETTINGS Case "C" Serout2 PORTC.6, 84, ["Recording time in hours (integer < 256)", 13] Serout2 PORTC.6, 84, ["The real recording time may be slightly higher (up to 128 seconds)than the entered time", 13] Serout2 PORTC.6, 84, ["Write and send the answer in DEC", 13] Serout2 PORTC.6, 84, 10, ["RECORDING_TIME : "] Serin2 PORTC.7, 84, [RECORDING_TIME] Write 0, Word RECORDING_TIME GoTo SETTINGS Case "D" Serout2 PORTC.6, 84, 10, [13, "Settings done ; the system will shutdown in 10 seconds."] Pause 5000 Goto FINISHED End Select Return '************************************************************************************************************************ '************************************************************************************************************************ READ_TIME : High RTC_CE ' Transfer enable RTC_IO_TRIS = 0 Shiftout RTC_IO, RTC_CLK, 0, [$BF] ' Read all 8 registers in burst mode RTC_IO_TRIS = 1 Shiftin RTC_IO, RTC_CLK, 1, [SECOND, MINUTE, HOUR, DATE, MONTH, DAY, YEAR, RTC_CTRL] Low RTC_CE ' Transfer disable Return '************************************************************************************************************************ '************************************************************************************************************************ FILE_DATING : ' Set file time and date to DS1302 time FAT_HOUR = HOUR.0 + 2 * HOUR.1 + 4 * HOUR.2 + 8 * HOUR.3 + 10 * (HOUR.4 + 2 * HOUR.5 + 4 * HOUR.6 + 8 * HOUR.7) FAT_MINUTE = MINUTE.0 + 2 * MINUTE.1 + 4 * MINUTE.2 + 8 * MINUTE.3 + 10 * (MINUTE.4 + 2 * MINUTE.5 + 4 * MINUTE.6 + 8 * MINUTE.7) FAT_SECOND = SECOND.1 + 2 * SECOND.2 + 4 * SECOND.3 + 5 * (SECOND.4 + 2 * SECOND.5 + 4 * SECOND.6 + 8 * SECOND.7) FAT_YEAR = YEAR.0 + 2 * YEAR.1 + 4 * YEAR.2 + 8 * YEAR.3 + 10 * (YEAR.4 + 2 * YEAR.5 + 4 * YEAR.6 + 8 * YEAR.7) + 20 FAT_MONTH = MONTH.0 + 2 * MONTH.1 + 4 * MONTH.2 + 8 * MONTH.3 + 10 * (MONTH.4 + 2 * MONTH.5 + 4 * MONTH.6 + 8 * MONTH.7) FAT_DATE = DATE.0 + 2 * DATE.1 + 4 * DATE.2 + 8 * DATE.3 + 10 * (DATE.4 + 2 * DATE.5 + 4 * DATE.6 + 8 * DATE.7) Return '************************************************************************************************************************ '************************************************************************************************************************ SD_INIT: ' Sending of 80 (10 x 8) empty clock cycles SD_CS = 1 For I = 1 TO 10 SHIFTOUT SDO, SCL, 5, [$FF] ' data out highest bit first, Clock idles high Next I SD_CS = 0 Pause 1 ' New delay of 16 clocks SHIFTOUT SDO, SCL, 5, [$FF] SHIFTOUT SDO, SCL, 5, [$FF] ' CMD0 sending SHIFTOUT SDO, SCL, 5, [$40,$00,$00,$00,$00,$95] SHIFTIN SDI, SCL, 6, [TYPE_1_CARD_REPLY] I = 0 While TYPE_1_CARD_REPLY <> 1 SHIFTIN SDI, SCL, 6, [TYPE_1_CARD_REPLY] I = I + 1 If I > 5000 Then FATAL_ERROR Wend SD_CS=1 Pause 1 SD_CS=0 'Serout2 PORTC.6, 84, ["Reset answer = ", IBIN8 TYPE_1_CARD_REPLY, 10, 13] 'Serout2 PORTC.6, 84, ["SD Init type1 card reply I = ", DEC I, 10, 13] ' CMD1 Card Initialization I = 0 TYPE_1_CARD_REPLY = 1 While TYPE_1_CARD_REPLY <> 0 SD_CS=1 SHIFTOUT SDO,SCL,5,[$FF] SHIFTIN SDI,SCL,6,[TYPE_1_CARD_REPLY] SD_CS=0 Pause 1 SHIFTOUT SDO, SCL, 5, [$41, $00, $00, $00, $00, $FF, $FF] 'CMD1 ; CRC7 not required SHIFTIN SDI,SCL,6,[TYPE_1_CARD_REPLY] I = I + 1 If I > 5000 Then FATAL_ERROR Wend 'Serout2 PORTC.6, 84, ["Now card in initialised ; I = ", DEC I, 10, 13] Return '************************************************************************************************************************ '************************************************************************************************************************ READ_BOOT_SECTOR: ' Read Boot sector written on the card during the FAT16 formatage SD_CS = 1 ' VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT SD_CS=0 VALUE_TO_SHIFT = $51 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT I = 0 While TYPE_1_CARD_REPLY<> 0 GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT I = I + 1 If I > 5000 Then FATAL_ERROR Wend ' Reading of the start of block token %11111110 preceding data GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT I = 0 While TYPE_1_CARD_REPLY<> %11111110 GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT I = I + 1 If I > 5000 Then FATAL_ERROR Wend ' Useful data recuperation from the BOOT sector For N = 1 to 12 ' We skip from $0000 to $000A (11 adresses) GoSub FAST_SHIFTIN Next N BYTES_PER_SECTOR.Byte0 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN BYTES_PER_SECTOR.Byte1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN SECTORS_PER_CLUSTER = VALUE_TO_SHIFT GoSub FAST_SHIFTIN RESERVED_SECTORS.Byte0 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN RESERVED_SECTORS.Byte1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN FAT_EXEMPLARS_NBR = VALUE_TO_SHIFT GoSub FAST_SHIFTIN ROOT_ENTRIES_NBR.Byte0 = VALUE_TO_SHIFT ' Adress $0011 GoSub FAST_SHIFTIN ROOT_ENTRIES_NBR.Byte1 = VALUE_TO_SHIFT For N = 1 to 4 ' We skip from $0013 to $0015 GoSub FAST_SHIFTIN Next N SECTORS_PER_FAT.Byte0 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN SECTORS_PER_FAT.Byte1 = VALUE_TO_SHIFT For I = 1 TO 488 GoSub FAST_SHIFTIN Next I ' CRC GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT ' CMD13 SD_CS=1 VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT SD_CS=0 VALUE_TO_SHIFT = $4D GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $0D GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE0 = VALUE_TO_SHIFT J=0 While TYPE_2_CARD_REPLY.BYTE0 <> 0 GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE0 = VALUE_TO_SHIFT J = J + 1 If J > 5000 Then FATAL_ERROR Wend Return '************************************************************************************************************************ '************************************************************************************************************************ CARD_ADDRESS_CALCULATION: CARD_ADRESS_LOW = 0 CARD_ADRESS_HIGH = 0 For J = 1 TO I CARD_ADRESS_LOW = CARD_ADRESS_LOW + $0200 If CARD_ADRESS_LOW = $0000 Then CARD_ADRESS_HIGH = CARD_ADRESS_HIGH + 1 EndIf Next J Return '************************************************************************************************************************ '************************************************************************************************************************ TIME_PLATEAU: Asm NOP NOP EndAsm Return '************************************************************************************************************************ ' The 2 following subroutines are dedicated to the SD card ports ' The assembler used is the Microchip MPASM v5.42 '************************************************************************************************************************ FAST_SHIFTIN: Asm BSF TRISC, 4 ; SDI port in BCF TRISC, 3 ; Clock port SLC out BCF PORTC, 3 ; Clock port SLC low MOVLW 7 ; Load 7 in the work register W MOVWF _BIT_COUNTER ; Save the W register value in _BIT_COUNTER CLRF _VALUE_TO_SHIFT ; Clear _VALUE_TO_SHIFT BEGIN BTFSC PORTC, 4 ; If SDI low, then skip following instruction INCF _VALUE_TO_SHIFT, 1 ; Increment _VALUE_TO_SHIFT BCF STATUS, C ; Clear Carry bit in STATUS register RLCF _VALUE_TO_SHIFT, 1 ; Rotate left _VALUE_TO_SHIFT using Carry bit BSF PORTC, 3 ; SLC high NOP ; 1 instruction delay BCF PORTC, 3 ; SLC low DECFSZ _BIT_COUNTER, 1 ; Decrement _BIT_COUNTER GoTo BEGIN ; BTFSC PORTC, 4 ; If SDI low, then jump to BSF INCF _VALUE_TO_SHIFT, 1 ; Increment _VALUE_TO_SHIFT BSF PORTC, 3 ; SLC high NOP ; 1 instruction delay BCF PORTC, 3 ; SLC low NOP ; 1 instruction delay EndAsm Return '************************************************************************************************************************ '************************************************************************************************************************ FAST_SHIFTOUT: Asm BCF TRISC, 5 ; SDO port out BCF TRISC, 3 ; SCL port out BCF PORTC, 3 ; SCL low MOVLW 8 ; Load 8 in the work register W MOVWF _BIT_COUNTER ; Save the W register in _BIT_COUNTER LABEL_1 BCF STATUS, C ; Clear Carry bit in STATUS register RLCF _VALUE_TO_SHIFT, 1 ; Rotate left _VALUE_TO_SHIFT using Carry bit BTFSS STATUS, C ; If Carry bit in STATUS register high, then skip following instruction GoTo LABEL_2 BSF PORTC, 5 ; SDO high GoTo LABEL_3 LABEL_2 BCF PORTC, 5 ; SDO low LABEL_3 BSF PORTC, 3 ; SCL high NOP ; 1 instruction delay BCF PORTC, 3 ; SCL low DECFSZ _BIT_COUNTER, 1 ; Decrement _BIT_COUNTER GoTo LABEL_1 NOP ; 1 instruction delay EndAsm Return '************************************************************************************************************************ '************************************************************************************************************************ WRITE_INIT: SD_CS=1 VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT 'CMD24 sending SD_CS=0 VALUE_TO_SHIFT = $58 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = CARD_ADRESS_HIGH.BYTE1 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = CARD_ADRESS_HIGH.BYTE0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = CARD_ADRESS_LOW.BYTE1 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = CARD_ADRESS_LOW.BYTE0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF ' CRC7 no required GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT J = 0 'Card reply reception While TYPE_1_CARD_REPLY <> 0 GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT J = J + 1 If J > 5000 Then FATAL_ERROR Wend 'Serout2 PORTC.6, 84, ["write init t1cr J = ", DEC J, 10, 13] VALUE_TO_SHIFT = $FE ' Starting block GoSub FAST_SHIFTOUT Return '************************************************************************************************************************ '************************************************************************************************************************ FATAL_ERROR : LED_GREEN = 0 LED_RED = 1 Pause 3000 GoTo FINISHED Return '************************************************************************************************************************ '************************************************************************************************************************ WRITE_END: ' Answer to write command analysis VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT CARD_REPLY_4BIT = %00000000 CARD_REPLY_4BIT = TYPE_1_CARD_REPLY & $0F If CARD_REPLY_4BIT <> %00000101 Then FATAL_ERROR ' Busy bit ; the answer time must be long (J > 1000) with some cards GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT J=0 While TYPE_1_CARD_REPLY = 0 GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT J = J + 1 If J > 10000 Then FATAL_ERROR Wend 'Serout2 PORTC.6, 84, ["write end - bit busy t1cr J = ", DEC J, 10, 13] ' CMD13 sending SD_CS=1 VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_1_CARD_REPLY = VALUE_TO_SHIFT SD_CS=0 VALUE_TO_SHIFT = $4D GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF ' CRC7 non required GoSub FAST_SHIFTOUT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE0 = VALUE_TO_SHIFT J=0 While TYPE_2_CARD_REPLY.BYTE0 <> 0 GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE1 = VALUE_TO_SHIFT GoSub FAST_SHIFTIN TYPE_2_CARD_REPLY.BYTE0 = VALUE_TO_SHIFT J = J + 1 If J > 5000 Then FATAL_ERROR Wend 'Serout2 PORTC.6, 84, ["write end type 2 cr J = ", DEC J, 10, 13] Return '************************************************************************************************************************ '************************************************************************************************************************ CLOSE_FILE: ' ROOT SECTOR CARD_ADRESS_LOW = ROOT_SECTOR_ADRESS_LOW CARD_ADRESS_HIGH = ROOT_SECTOR_ADRESS_HIGH GoSub WRITE_INIT ' File name and attributes GoSub FILE_NAMING ' Name file recording on the card (made from the beginning date and hour) For N = 0 TO 2 VALUE_TO_SHIFT = 0 GoSub FAST_SHIFTOUT Next N ' Creation hour and date ; here time and hour are the beginning ones VALUE_TO_SHIFT = FAT_HMS.Byte0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_HMS.Byte1 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_YMD.Byte0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_YMD.Byte1 GoSub FAST_SHIFTOUT For N = 18 TO 21 VALUE_TO_SHIFT = 0 GoSub FAST_SHIFTOUT Next N ' Cloture hour and date (written in "last modification" entry) GoSub READ_TIME GoSub FILE_DATING ' Here time and hour are end of recording ones FAT_HMS = FAT_SECOND | (FAT_MINUTE << 5) | (FAT_HOUR << 11) 'FAT16 format for Date and Time FAT_YMD = FAT_DATE | (FAT_MONTH << 5) | (FAT_YEAR << 9) VALUE_TO_SHIFT = FAT_HMS.Byte0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_HMS.Byte1 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_YMD.Byte0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FAT_YMD.Byte1 GoSub FAST_SHIFTOUT ' First cluster number VALUE_TO_SHIFT = $2 GoSub FAST_SHIFTOUT VALUE_to_SHIFT = 0 GoSub FAST_SHIFTOUT ' File size VALUE_TO_SHIFT = FILE_LENGTH_LOW.BYTE0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FILE_LENGTH_LOW.BYTE1 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FILE_LENGTH_HIGH.BYTE0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = FILE_LENGTH_HIGH.BYTE1 GoSub FAST_SHIFTOUT For K = 32 TO 511 VALUE_TO_SHIFT = 0 GoSub FAST_SHIFTOUT Next K GoSub WRITE_END ' FAT1 Sector If SECTOR_CNTR <> 0 Then CLUSTER_CNTR = CLUSTER_CNTR + 3 Else CLUSTER_CNTR = CLUSTER_CNTR + 2 EndIf L = $0003 ' First cluster CARD_ADRESS_LOW = FAT_SECTOR_ADRESS_LOW CARD_ADRESS_HIGH = FAT_SECTOR_ADRESS_HIGH GoSub WRITE_INIT VALUE_TO_SHIFT = $F8 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF For N = 1 TO 3 GoSub FAST_SHIFTOUT Next N K = 4 While L < CLUSTER_CNTR VALUE_TO_SHIFT = L.BYTE0 GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = L.BYTE1 GoSub FAST_SHIFTOUT K = K + 2 L = L + 1 If K = 512 Then GoSub WRITE_END K = 0 CARD_ADRESS_LOW = CARD_ADRESS_LOW + $0200 If CARD_ADRESS_LOW = $0000 Then CARD_ADRESS_HIGH = CARD_ADRESS_HIGH + 1 EndIf GoSub WRITE_INIT EndIf Wend VALUE_TO_SHIFT = $FF ' End of file GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = $FF GoSub FAST_SHIFTOUT K = K + 2 While K < 512 VALUE_TO_SHIFT = $00 GoSub FAST_SHIFTOUT K = K + 1 Wend GoSub WRITE_END Return '************************************************************************************************************************ '************************************************************************************************************************ DIGITIZE : ADC_CS = 1 ADC_SCLK = 1 SAMPLE = 0 ADC_CS = 0 ' Sampling enabled For N = 1 TO 4 ' Send the 4 leading zeros ADC_SCLK = 0 ' Setting of the ADC clock crenel function GoSub TIME_PLATEAU ADC_SCLK = 1 GoSub TIME_PLATEAU Next N For N = 1 TO 15 ' Sampling of the 15 first bits ADC_SCLK = 0 If ADC_SDATA = 1 Then ' Progressive setting of the word type variable SAMPLE SAMPLE = SAMPLE + 1 EndIf SAMPLE = SAMPLE << 1 GoSub TIME_PLATEAU ADC_SCLK = 1 GoSub TIME_PLATEAU Next N ADC_SCLK = 0 If ADC_SDATA = 1 Then ' Sampling of the 16th bit SAMPLE = SAMPLE + 1 EndIf GoSub TIME_PLATEAU ADC_SCLK = 1 GoSub TIME_PLATEAU For N = 1 TO 4 ' Send the 4 trailing zeros ADC_SCLK = 0 GoSub TIME_PLATEAU ADC_SCLK = 1 GoSub TIME_PLATEAU Next N ADC_CS = 1 ' Sampling disabled Return '************************************************************************************************************************ '************************************************************************************************************************ FILE_NAMING : ' File name format : MMDDHHMM.DAT GoSub FILE_DATING ' Bytes sent must be ASCII codes of characters constituting the file name ArrayWrite FILE_NAME, [DEC FAT_MONTH / 10, DEC FAT_MONTH // 10, DEC FAT_DATE / 10, DEC FAT_DATE // 10, DEC FAT_HOUR / 10, DEC FAT_HOUR // 10, DEC FAT_MINUTE / 10, DEC FAT_MINUTE // 10] For N = 0 to 7 ArrayRead FILE_NAME, [Skip N, VALUE_TO_SHIFT] GoSub FAST_SHIFTOUT Next N VALUE_TO_SHIFT = "D" GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = "A" GoSub FAST_SHIFTOUT VALUE_TO_SHIFT = "T" GoSub FAST_SHIFTOUT Return '************************************************************************************************************************