/* * This file is part of the Bus Pirate project (http://code.google.com/p/the-bus-pirate/). * * Written and maintained by the Bus Pirate project. * * To the extent possible under law, the project has * waived all copyright and related or neighboring rights to Bus Pirate. This * work is published from United States. * * For details see: http://creativecommons.org/publicdomain/zero/1.0/. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include "SPI.h" #include "base.h" #include "procMenu.h" #ifdef BP_USE_LCD //direction registers #define SPIMOSI_TRIS BP_MOSI_DIR #define SPICLK_TRIS BP_CLK_DIR #define SPIMISO_TRIS BP_MISO_DIR #define SPICS_TRIS BP_CS_DIR //pin control registers #define SPIMOSI BP_MOSI #define SPICLK BP_CLK #define SPIMISO BP_MISO #define SPICS BP_CS //Define how the PCF8574 pins connect to the LCD #define HCT595_LCD_LED 0b00000001 #define HCT595_LCD_RS 0b00000010 #define HCT595_LCD_RW 0b00000100 #define HCT595_LCD_EN 0b00001000 #define HCT595_LCD_D4 0b00010000 #define HCT595_LCD_D5 0b00100000 #define HCT595_LCD_D6 0b01000000 #define HCT595_LCD_D7 0b10000000 //RS (register select) pin states #define HD44780_COMMAND 0 #define HD44780_DATA 1 // //HD44780 commands and related options // #define CMD_CLEARDISPLAY 0b00000001 //82us-1.64ms #define CMD_RETURNHOME 0b00000010 //40us-1.64ms #define CMD_ENTRYMODESET 0b00000100 //40us #define INCREMENT 0b10 #define DECREMENT 0b00 #define DISPLAYSHIFTON 0b1 #define DISPLAYSHIFTOFF 0 #define CMD_DISPLAYCONTROL 0b00001000 //40us #define DISPLAYON 0b100 #define DISPLAYOFF 0 #define CURSERON 0b10 #define CURSEROFF 0 #define BLINKON 0b1 #define BLINKOFF 0 #define CMD_CURSERDISPLAYSHIFT 0b00010000 //40us #define DISPLAYSHIFT 0b1000 #define CURSERMOVE 0 #define SHIFTRIGHT 0b100 #define SHIFTLEFT 0 #define CMD_FUNCTIONSET 0b00100000 //40us #define DATAWIDTH8 0b10000 #define DATAWIDTH4 0 #define DISPLAYLINES2 0b1000 #define DISPLAYLINES1 0 #define FONT5X10 0b100 #define FONT5X7 0 #define MODULE24X4 0b1 #define CMD_SETCGRAMADDR 0b01000000 //40us //6bit character generator RAM address #define CMD_SETDDRAMADDR 0b10000000 //40us //7bit display data RAM address //configuration structure extern struct _modeConfig modeConfig; extern struct _command bpCommand; struct _HD44780_interface { unsigned char EN:1; //clock, active high unsigned char RS:1; //register select, 0=command, 1=text unsigned char RW:1; //read write, 0=write, 1=read unsigned char LED:1; //LED on IO board, 0=on, 1=off //unsigned char dat; //8 data bits } HD44780; void HD44780_Reset(void); //reset the LCD to 4 bit mode void HD44780_Init(unsigned char displaylines); //initialize LCD to 4bit mode with typical settings and X displaylines void HD44780_WriteString(char *s); //write a string to the LCD void HD44780_WriteByte(unsigned char reg, unsigned char dat); //write a byte to LCD to register REG void HD44780_WriteNibble(unsigned char reg, unsigned char dat);//write 4 bits to LCD to register REG void HD44780_SPIwrite(unsigned char datout); //abstracts data output to PCF8574 IO expander over I2C bus void LCDsetup_exc(void); unsigned int LCDwrite(unsigned int c) { HD44780_WriteByte(HD44780.RS, c); return 0x100; } void LCDstart(void) { HD44780.RS=HD44780_COMMAND; //bpWline(OUMSG_LCD_COMMAND_MODE); BPMSG1213; } void LCDstop(void) { HD44780.RS=HD44780_DATA; //bpWline(OUMSG_LCD_DATA_MODE); BPMSG1214; } void LCDsetup(void) { modeConfig.HiZ=1;//yes, always HiZ } void LCDsetup_exc(void) { HD44780.RS=HD44780_DATA; /* consumewhitechars(); type=getint(); consumewhitechars(); address=getint(); if(!((type==1)&&(address>=0x00)&&(address<=0xFF))) { cmderror=0; //bpWline(OUMSG_LCD_SETUP_ADAPTER); BPMSG1217; //c=bpUserNumberPrompt(1, 1, 1); getnumber(1,1,1,0); // schiet mij maar in een kapotje :S // address of expander? BPMSG1215; HD44780.PCF8574=getnumber(0x40,0, 255, 0); } else { BPMSG1218; bpWdec(type); bpSP; bpWdec(address); bpSP; BPMSG1162; HD44780.PCF8574=address; } */ //PPS Setup // Inputs RPINR20bits.SDI1R = BP_MISO_RPIN; //MISO // Outputs BP_MOSI_RPOUT = SDO1_IO; //B9 MOSI BP_CLK_RPOUT = SCK1OUT_IO; //B8 CLK // #if defined(BUSPIRATEV3) // // Inputs // RPINR20bits.SDI1R = 7; //B7 MISO // // Outputs // RPOR4bits.RP9R = SDO1_IO; //B9 MOSI // RPOR4bits.RP8R = SCK1OUT_IO; //B8 CLK // #elif defined(BUSPIRATEV4) // // Inputs // RPINR20bits.SDI1R = 22; //B7 MISO // // Outputs // RPOR12bits.RP24R = SDO1_IO; //B9 MOSI // RPOR11bits.RP23R = SCK1OUT_IO; //B8 CLK // #endif SPICS=0; //B6 cs low SPICS_TRIS=0; //B6 cs output //pps configures pins and this doesn't really matter.... SPICLK_TRIS=0; //B8 sck output SPIMISO_TRIS=1; //B7 SDI input SPIMOSI_TRIS=0; //B9 SDO output /* CKE=1, CKP=0, SMP=0 */ SPI1CON1 = 0b0100111101;//(SPIspeed[modeConfig.speed]); // CKE (output edge) active to idle, CKP idle low, SMP data sampled middle of output time. //SPI1CON1=0b11101; //SPI1CON1bits.MSTEN=1; //SPI1CON1bits.CKP=0; //SPI1CON1bits.CKE=1; //SPI1CON1bits.SMP=0; SPI1CON2 = 0; SPI1STAT = 0; // clear SPI SPI1STATbits.SPIEN = 1; //bpWmessage(MSG_ADAPTER); BPMSG1216; } void LCDmacro(unsigned int c) { int input,i; cmdstart=(cmdstart+1)&CMDLENMSK; //cmdstart&=CMDLENMSK; consumewhitechars(); input=getint(); cmderror=0; switch(c) { case 0://menu //bpWline(OUMSG_LCD_MACRO_MENU); BPMSG1219; break; case 1: case 2: //bpWline(OUMSG_LCD_MACRO_RESET); BPMSG1093; HD44780_Reset(); if(c==1) break; if(!((input>=1)&&(input<=2))) { //bpWline(OUMSG_LCD_MACRO_INIT_DISPLAYLINES); BPMSG1220; //c=bpUserNumberPrompt(1, 2, 2); input=getnumber(2,1,2, 0); if(input==1) HD44780_Init(DISPLAYLINES1); else HD44780_Init(DISPLAYLINES2); //bpWline(OUMSG_LCD_MACRO_INIT); } BPMSG1221; break; case 3: //Clear LCD and return home HD44780_WriteByte(HD44780_COMMAND, CMD_CLEARDISPLAY); bpDelayMS(15);//delay 15ms //bpWline(OUMSG_LCD_MACRO_CLEAR); BPMSG1222; break; case 4: HD44780_WriteByte(HD44780_COMMAND, CMD_SETDDRAMADDR | (unsigned char)input); //bpWline(OUMSG_LCD_MACRO_CURSOR); BPMSG1223; break; case 6: //write numbers HD44780_WriteByte(HD44780_COMMAND, CMD_CLEARDISPLAY);//Clear LCD and return home bpDelayMS(15);//delay 15ms c=0x30; if(input==0) input=80; for(i=0; i0x39) c=0x30; HD44780_WriteByte(HD44780_DATA, c); UART1TX(c); c++; } break; case 7://write characters HD44780_WriteByte(HD44780_COMMAND, CMD_CLEARDISPLAY); //Clear LCD and return home bpDelayMS(15);//delay 15ms c=0x21; //start character (!) if(input==0) input=80; for(i=0; i127)c=0x21; HD44780_WriteByte(HD44780_DATA, c); UART1TX(c); c++; } break; /* case 8://terminal mode/pass through //superseeded by send string command bpWline(OUMSG_LCD_MACRO_TEXT); HD44780_Term(); break; */ default: //bpWmessage(MSG_ERROR_MACRO); BPMSG1016; } } void LCDpins(void) { #if defined(BUSPIRATEV4) BPMSG1261; //bpWline("-\t-\tSCL\tSDA"); #else BPMSG1231; //bpWline("SCL\tSDA\t-\t-"); #endif } //initialize LCD to 4bits with standard features //displaylines=0 for single line displays, displaylines=1 for multiline displays void HD44780_Init(unsigned char displaylines){ //Function set HD44780_WriteByte(HD44780_COMMAND, (CMD_FUNCTIONSET + DATAWIDTH4 + FONT5X7 + displaylines)); //0x28, 0b101000 bpDelayMS(15);//delay 15ms //Turn display off HD44780_WriteByte(HD44780_COMMAND, CMD_DISPLAYCONTROL + DISPLAYOFF + CURSEROFF + BLINKOFF);//0x08, 0b1000 bpDelayMS(15);//delay 15ms //Clear LCD and return home HD44780_WriteByte(HD44780_COMMAND, CMD_CLEARDISPLAY); bpDelayMS(15);//delay 15ms //Turn on display, turn off cursor and blink HD44780_WriteByte(HD44780_COMMAND, CMD_DISPLAYCONTROL + DISPLAYON + CURSERON + BLINKOFF); // 0x0f, 0b1111 bpDelayMS(15);//delay 15ms } //reset LCD to 4bit mode void HD44780_Reset(void){ HD44780_SPIwrite(0); //clear IO pins to HD44780 //# Wait more than 15 msecs after power is applied. bpDelayMS(15); //# Write 0x03 to LCD and wait 5 msecs for the instruction to complete HD44780_WriteNibble(HD44780_COMMAND, 0x03); bpDelayMS(5); //# Write 0x03 to LCD and wait 160 usecs for instruction to complete HD44780_WriteNibble(HD44780_COMMAND, 0x03); bpDelayUS(160); //# Write 0x03 AGAIN to LCD and wait 160 usecs (or poll the Busy Flag) HD44780_WriteNibble(HD44780_COMMAND, 0x03); bpDelayUS(160); //Set the Operating Characteristics of the LCD //* Write 0x02 to the LCD to Enable Four Bit Mode HD44780_WriteNibble(HD44780_COMMAND, 0x02); bpDelayUS(160); } //write byte dat to register reg void HD44780_WriteByte(unsigned char reg, unsigned char dat){ HD44780_WriteNibble(reg, (dat>>4) ); HD44780_WriteNibble(reg, (dat & 0x0F)); } //write 4 bits dat to register reg void HD44780_WriteNibble(unsigned char reg, unsigned char dat){ //EN pin should already be low //RW bit should be 0 (already 0 in dat) //LED bit should be 0 (already 0 in dat) //databits are aligned with the upper four bits of 595 //push them from the lower four bits of dat ot the upper four bits dat=dat<<4; dat|=HCT595_LCD_LED; //keep LED on if(reg==HD44780_DATA){ //does RS need to be set? dat |= HCT595_LCD_RS; //set register select flag for text }//leave as 0 for a command HD44780_SPIwrite(dat); //load values dat |= HCT595_LCD_EN; //raise the EN line to clock in the values HD44780_SPIwrite(dat); //optional setup delay dat &= (~HCT595_LCD_EN); //lower EN line HD44780_SPIwrite(dat); } #ifndef BP_MAIN //open drain control registers for OUTPUT pins #define SPIMOSI_ODC BP_MISO_ODC #define SPICLK_ODC BP_CLK_ODC #define SPICS_ODC BP_CS_ODC // copied from spi.c, but with thesplitfirmware it was gone.. unsigned char spiWriteByte(unsigned char c){ SPI1BUF = c; while(!IFS0bits.SPI1IF); c=SPI1BUF; IFS0bits.SPI1IF = 0; return c; } void spiDisable(void){ SPI1STATbits.SPIEN = 0; RPINR20bits.SDI1R=0b11111; //B7 MISO //PPS Disable BP_MOSI_RPOUT=0; BP_CLK_RPOUT=0; // #if defined(BUSPIRATEV3) // RPOR4bits.RP9R=0; //B9 MOSI // RPOR4bits.RP8R=0; //B8 CLK // #elif defined(BUSPIRATEV4) // RPOR12bits.RP24R=0; //B9 MOSI // RPOR11bits.RP23R=0; //B8 CLK // #endif //disable all open drain control register bits SPIMOSI_ODC=0; SPICLK_ODC=0; SPICS_ODC=0; //make all input maybe??? } #endif //write value to 595 IO expander, message and return on ACK error void HD44780_SPIwrite(unsigned char datout){ spiWriteByte(datout); SPICS=1; //bpDelayUS(255); SPICS=0; } #endif