;------------------------------------------------------------------------------- ; FILE: SPI OLED ; AUTH: Ed's Projects ; DATE: 24/09/2016 ; DESC: Display bmp image from SD card to OLED display. ;------------------------------------------------------------------------------- LIST P=16F887, R=DEC ; All numbers Decimal format unless otherwise stated. include ; Define configurations, registers, etc. __CONFIG _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOREN_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDTE_OFF & _HS_OSC ;------------------------------------------------------------------------------- ;-------------------------------- Variables ---------------------------------- ;------------------------------------------------------------------------------- cblock h'20' temp temp2 temp3 temp4 temp5 bitH spbitH spbitL Ent0 Ent1 Ent2 Ent3 Ent4 Ent5 Ent6 Ent7 Ent8 Ent9 Ent10 Adr32 Adr24 Adr16 Adr8 endc ;------------------------------------------------------------------------------- ;----------------------------- Define Symbols -------------------------------- ;------------------------------------------------------------------------------- #define DC PORTD, 5 #define RW PORTD, 6 #define E PORTD, 7 #define BUS PORTB #define CS PORTD, 4 #define SDCS PORTC, 2 #define SDPS PORTA, 5 ;------------------------------------------------------------------------------- ;------------------------------- Program Code -------------------------------- ;------------------------------------------------------------------------------- ORG 0 ;------------------------------------------------------------------------------- ;-------------------------- Initialisation of Ports -------------------------- ;------------------------------------------------------------------------------- Init bcf STATUS,RP0 bcf STATUS,RP1 ; Bank 0 Selected clrf ADCON0 ; Turn off ADC bsf STATUS,RP0 ; Bank 1 Selected clrf VRCON ; Set Vref to off movlw b'00111111' movwf TRISA clrf TRISB ; Set all PortB as Output movlw b'11010000' movwf TRISC clrf TRISD ; Set all PortD as Output movlw b'00000000' movwf TRISE bsf STATUS,RP1 ; Bank 3 Selected clrf ANSEL ; Set all high analogue inputs to digital clrf ANSELH ; Set all high analogue inputs to digital bcf STATUS,RP0 ; Bank 2 Selected clrf CM1CON0 ; Turn off comparator 1 clrf CM2CON0 ; Turn off comparator 2 bcf STATUS,RP0 bcf STATUS,RP1 ; Bank 0 Selected clrf PORTA clrf PORTB clrf PORTC clrf PORTD clrf PORTE ;------------------------------------------------------------------------------- ;----------------------------- SPI Initialisation ---------------------------- ;------------------------------------------------------------------------------- movlw b'00110000' ; Serial port enable, 5MHz movwf SSPCON ; Clock polarity idle high bsf STATUS, RP0 ; Bank 1 selected bcf SSPSTAT, CKE bcf STATUS, RP0 ; Bank 0 selected; bsf SDCS ; Deselect chip 1 ;------------------------------------------------------------------------------- ;-------------------------------- Initialisaton ------------------------------ ;------------------------------------------------------------------------------- movlw d'16' call delay1 ; Wait 2 second goto LCDinit ;------------------------------------------------------------------------------- ;--------------------------- Send and Receive Serial -------------------------- ;------------------------------------------------------------------------------- SPI movwf temp movf SSPBUF, w ; Clear buffer full flag movf temp, w movwf SSPBUF ; Send data bsf STATUS, RP0 ; Bank 1 selected btfss SSPSTAT, BF goto $-1 ; Check if sent bcf STATUS, RP0 ; Bank 0 selected return ;------------------------------------------------------------------------------- ;-------------------------------- Delay Loops -------------------------------- ;------------------------------------------------------------------------------- delay1 movwf temp4 loopy2 movlw d'125' movwf temp3 loopy movlw d'250' movwf temp initloop goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns goto $+1 ;400ns nop ;200ns decfsz temp, f ;200ns goto initloop ;400ns decfsz temp3, f goto loopy ;250ms total decfsz temp4, f goto loopy2 ;Multiples of 250ms return ;------------------------------------------------------------------------------- ;-------------------------------- Send to LCD -------------------------------- ;------------------------------------------------------------------------------- LCD movwf BUS bsf E bcf E return ;------------------------------------------------------------------------------- ;---------------------------- LCD Initialisation ----------------------------- ;------------------------------------------------------------------------------- LCDinit bcf CS bcf RW bcf DC movlw b'00010101' call LCD ; Set Column Address movlw b'00000000' call LCD ; Column Start 0 movlw b'00111111' call LCD ; Column End 63 = 128 segments movlw b'01110101' call LCD ; Set Row Address movlw b'00001101' call LCD ; Row Start 13 movlw b'01001100' call LCD ; Row End 76 = 64 segments movlw b'10000001' call LCD ; Set Contrast movlw b'01000000' call LCD ; Contrast movlw b'10100000' call LCD ; Set Remap movlw b'01010001' call LCD ; Set horizontal increment, COM split, ; Column address invert, COM invert movlw b'10100001' call LCD ; Set Start Line movlw b'00000000' call LCD ; Display Start Line 0 movlw b'10100010' call LCD ; Set Offset movlw b'00001001' call LCD ; Offset 9 movlw h'A4' call LCD ; Display Normal movlw b'10000111' call LCD ; Full Current movlw b'10110011' call LCD ; Display clock and frequency movlw b'00000000' call LCD movlw b'11110000' ; Highest clock frequency call LCD movlw h'AF' call LCD ; Display on bsf DC ; Write Data movlw d'128' movwf temp3 movlw d'32' movwf temp2 clrloop clrw ; Clear Display RAM call LCD decfsz temp3, f goto clrloop movlw d'128' movwf temp3 decfsz temp2, f goto clrloop bcf DC ; Command movlw b'10100001' call LCD ; Set Start Line movlw b'00000000' call LCD ; Display Start Line 0 bsf DC ; Write Data goto Start ;------------------------------------------------------------------------------- ;----------------------------- Initialise SD Card ---------------------------- ;------------------------------------------------------------------------------- SDinit btfss SDPS ; Check if card Inserted goto SDinit movlw b'00110010' ; Serial port enable, 312.5kHz movwf SSPCON ; Clock polarity idle high movlw d'16' ; Delay of 2 seconds call delay1 notint bsf SDCS ; Deselect SD Card movlw d'255' call SPI movlw d'255' ; Send a total of 80 clock pulses call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI ;------------------------------------------------------------------------------- bcf SDCS ; Select SD Card movlw b'01000000' ; Command 0 call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw b'10010101' ; CRC call SPI movlw d'255' ; NCR call SPI movlw d'255' ; Send to Receive Response call SPI movf SSPBUF, w xorlw b'00000001' btfss STATUS, Z goto notint ; An error?, try again bsf SDCS ; Deselect SD Card ;------------------------------------------------------------------------------- bcf SDCS ; Select SD Card movlw b'01001000' ; Command 8 call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'1' call SPI movlw b'10101010' call SPI movlw b'10000111' call SPI movlw d'255' call SPI movlw d'255' call SPI movf SSPBUF, w xorlw b'00000001' btfss STATUS, Z goto notint movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movlw d'255' call SPI movf SSPBUF, w xorlw b'10101010' ; Result AA - SD Version 2 btfss STATUS, Z goto notint bsf SDCS ; Deselect SD Card ;------------------------------------------------------------------------------- loop55 bcf SDCS ; Select SD Card movlw b'01110111' ; Command ACMD41 call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'1' call SPI movlw d'255' call SPI movlw d'255' call SPI movf SSPBUF, w addlw d'0' btfsc STATUS, Z goto done movlw b'01101001' ; Command 55 call SPI movlw b'01000000' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'1' call SPI movlw d'255' call SPI movlw d'255' call SPI bsf SDCS ; Deselect SD Card movf SSPBUF, w addlw d'0' btfss STATUS, Z goto loop55 ;------------------------------------------------------------------------------- done movlw b'00110000' ; Serial port enable, 5MHz movwf SSPCON ; Clock polarity idle high ;Now Ready to read return ;------------------------------------------------------------------------------- ;-------------------- Read Specific Location From SD Card -------------------- ;------------------------------------------------------------------------------- ReadSD bcf SDCS ; Select SD Card movlw b'01010010' ; Command 18 call SPI movf Adr32, w call SPI movf Adr24, w call SPI movf Adr16, w call SPI movf Adr8, w call SPI movlw d'1' ; Checksum call SPI movlw d'255' call SPI movlw d'255' ; R1 response call SPI lpagain movlw d'255' ; Check if start token received call SPI movf SSPBUF, w xorlw b'11111110' btfss STATUS, Z goto lpagain movlw d'4' movwf spbitH movlw d'128' movwf spbitL return ;------------------------------------------------------------------------------- ;------------------------------- Read Directory ------------------------------ ;------------------------------------------------------------------------------- Diread movlw d'31' movwf temp2 call SPIMUL movwf temp xorlw h'E5' btfsc STATUS, Z goto delent ; If set we want to skip to next entry movf temp, w xorwf Ent0, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent1, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent2, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent3, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent4, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent5, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent6, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent7, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent8, w btfss STATUS, Z goto delent decf temp2, f call SPIMUL xorwf Ent9, w btfss STATUS, Z goto delent ; All the entries in between decf temp2, f call SPIMUL xorwf Ent10, w btfss STATUS, Z goto delent ; Our entry matches call SPIMUL ; Discard attributes call SPIMUL ; Discard reserved call SPIMUL ; Discard file creation time call SPIMUL ; Discard file creation time call SPIMUL ; Discard file creation time call SPIMUL ; Discard file creation date call SPIMUL ; Discard file creation date call SPIMUL ; Discard file access date call SPIMUL ; Discard file access date call SPIMUL movwf Adr24 ; High cluster offset call SPIMUL movwf Adr32 ; High cluster offset call SPIMUL ; Discard file modification time call SPIMUL ; Discard file modification time call SPIMUL ; Discard file modification date call SPIMUL ; Discard file modification date call SPIMUL movwf Adr8 ; Low cluster offset call SPIMUL movwf Adr16 ; Low cluster offset call Edcmd ; End read command movlw d'2' ; Minus 2 as our root directory starts at 2 subwf Adr8 btfsc STATUS, C goto nxtmul movlw d'1' subwf Adr16 btfsc STATUS, C goto nxtmul movlw d'1' subwf Adr24 btfsc STATUS, C goto nxtmul decf Adr32, f nxtmul clrc rlf Adr8, f rlf Adr16, f rlf Adr24, f rlf Adr32, f rlf Adr8, f rlf Adr16, f rlf Adr24, f rlf Adr32, f rlf Adr8, f rlf Adr16, f rlf Adr24, f rlf Adr32, f rlf Adr8, f rlf Adr16, f rlf Adr24, f rlf Adr32, f rlf Adr8, f rlf Adr16, f rlf Adr24, f rlf Adr32, f ; Multiply our offset by 32 movlw d'96' ; Add our root directory location addwf Adr16 btfss STATUS, C return movlw d'1' addwf Adr24 btfss STATUS, C return incf Adr32, f return delent call SPIMUL decfsz temp2, f goto delent goto Diread ;------------------------------------------------------------------------------- ;---------------------------------- End Read --------------------------------- ;------------------------------------------------------------------------------- Edcmd movlw b'01001100' ; Command 12 call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'0' call SPI movlw d'1' call SPI movlw d'255' call SPI lpend movlw d'255' call SPI movf SSPBUF, w addlw d'0' btfss STATUS, Z goto lpend bsf SDCS ; Deselect SD Card return ;------------------------------------------------------------------------------- ;----------------------- Read Bitmap from SD to Display ---------------------- ;------------------------------------------------------------------------------- Bmpread movlw d'2' ; Increment past useless image data addwf Adr8 btfss STATUS, C goto bmpsk movlw d'1' addwf Adr16 btfss STATUS, C goto bmpsk movlw d'1' addwf Adr24 btfss STATUS, C goto bmpsk incf Adr32, f bmpsk call ReadSD ; Get to location of our image movlw d'54' movwf temp5 label2 call SPIMUL decfsz temp5, f goto label2 movlw d'64' movwf temp3 movlw d'64' movwf temp2 lcdloop call Congrey ; Display Image to LCD decfsz temp3, f goto lcdloop movlw d'64' movwf temp3 decfsz temp2, f goto lcdloop call Edcmd ; End read command return Congrey call SPIMUL ; Convert 2 bytes to 1 byte = 2 pixels movwf bitH bcf bitH, 0 bcf bitH, 1 bcf bitH, 2 bcf bitH, 3 movf bitH, w xorlw d'240' btfsc STATUS, Z bcf bitH, 4 call SPIMUL call grey addwf bitH movf bitH, w xorlw d'255' ; Invert Pixels call LCD return grey movwf temp clrc rrf temp, f clrc rrf temp, f clrc rrf temp, f clrc rrf temp, f clrc movf temp, w xorlw d'15' btfsc STATUS, Z bcf temp, 0 movf temp, w return SPIMUL movlw d'255' ; Check we only read 512 bytes before discarding call SPI ; CRC and check for start token movf SSPBUF, w decfsz spbitL, f return movlw d'128' movwf spbitL movf SSPBUF, w movwf temp4 decfsz spbitH, f return movlw d'4' movwf spbitH movlw d'255' call SPI ; CRC movlw d'255' call SPI ; CRC lptoken movlw d'255' ; Check for start token call SPI movf SSPBUF, w xorlw b'11111110' btfss STATUS, Z goto lptoken movf temp4, w return ;------------------------------------------------------------------------------- ;-------------------------------- Main Program ------------------------------- ;------------------------------------------------------------------------------- Start call SDinit clrf Adr32 clrf Adr24 movlw b'01100000' movwf Adr16 clrf Adr8 call ReadSD ; Start at root directory movlw "E" movwf Ent0 movlw "N" movwf Ent1 movlw "G" movwf Ent2 movlw "I" movwf Ent3 movlw "N" movwf Ent4 movlw "E" movwf Ent5 movlw h'20' movwf Ent6 movlw h'20' movwf Ent7 movlw h'20' movwf Ent8 movlw h'20' movwf Ent9 movlw h'20' movwf Ent10 call Diread call ReadSD movlw "P" movwf Ent0 movlw "I" movwf Ent1 movlw "C" movwf Ent2 movlw "T" movwf Ent3 movlw "U" movwf Ent4 movlw "R" movwf Ent5 movlw "E" movwf Ent6 movlw "S" movwf Ent7 movlw h'20' movwf Ent8 movlw h'20' movwf Ent9 movlw h'20' movwf Ent10 call Diread call ReadSD movlw "C" movwf Ent0 movlw "A" movwf Ent1 movlw "T" movwf Ent2 movlw "2" movwf Ent3 movlw h'20' movwf Ent4 movlw h'20' movwf Ent5 movlw h'20' movwf Ent6 movlw h'20' movwf Ent7 movlw "B" movwf Ent8 movlw "M" movwf Ent9 movlw "P" movwf Ent10 call Diread call Bmpread goto $ end