BIT BANG MCP23S17

General discussion on mikroC PRO for PIC.
Post Reply
Author
Message
zdavesf
Posts: 43
Joined: 10 May 2007 03:52

BIT BANG MCP23S17

#1 Post by zdavesf » 06 Jan 2010 01:54

Hello all. I am trying to write my own bit bang SPI code for reading and writing to the wonderful MCP23S17 io expander using a PIC18F4550 using 4mhz oscillator with pll at 48Mhz (i have usb working separate and will be added after this all works). (i am beginning to think if i should use the PCF8575 I2C expander that i already know how to operate...). I have a 128x64 glcd working properly so i know my config/timings are set correctly. Just in case your wondering i have a dual monitor display. one has mikroC open the other has the MCP23s17 datasheet, yes i have been reading it alot.

here's the deal, it sort of works when writing... i have been just testing my routines with a simple loop of altering leds on two of the outputs (i have shut all my interrupts off for testing). it works for about 2-3 seconds and then stops...

while(1) {
data_a=~data_a;
MCP2317_WRITE(MCP_OLATA,data_a);
delay_ms(300);
}//end while loop

reading a button press works only once and then corresponding INTB pin stays set(reading page 25 of data sheet says this should only occur as long as readbit is same as register bit ie. until button it let go). if have tried different configurations of reading GPIO and INCAP registers as well as enabling/disabling the INTCONB register.

any suggestions, comments or ideas would be greatly appreciated. I need to use the interrupt pins which are also the hardware MSSP pins so i need a soft spi library(which mikroc has) but i also need clock clock data on falling edge (for the AD55453 dac). It would just be nice to be able to get this to work... i think im close. I have a 2channel USB scope that i have been monitoring data with, clock is around 666Khz. thank you ever so much. Dave

Code: Select all

// CONFIG_SPI
     #define SPI_SDO       LATC.F7
     #define SPI_CLK       LATC.F6
     #define SPI_SDI       PORTC.F2
     #define MCP2317_EN    LATC.F1
     #define MCP_RESET     LATC.F0
     #define MCP_INTB      PORTB.F5
     #define AD5453_LEN    LATE.F1
     #define AD5453_REN    LATE.F2

     #define MCP_OPCODE_WRITE 0b01001110 // hpen enabled
     #define MCP_OPCODE_READ  0b01001111 

//************** REGISTER ADDRESSES ******************************
//**************** IOCON.BANK = 1 ********************************

     #define MCP_IODIRA 0x00
     #define MCP_IODIRB 0x10
     #define MCP_IPOLA 0x01    //input polarity, 1=GPIO register bit will reflect
     #define MCP_IPOLB 0x11    //opposite logic of input, 0 will be the same
     #define MCP_GPINTENA 0x02 //interrupt on change, defval and intcon register must be altered
     #define MCP_GPINTENB 0x12 //1= enable interrupt on change, 0 disable 
     #define MCP_DEFVALA 0x03  //enabled via GPINTEN and INTCON, oppostite value on pin will
     #define MCP_DEFVALB 0X13  //cause interrupt to occur, these bits set the value to compare, set as pull up/down value
     #define MCP_INTCONA 0X04  //interrupt control register if bit is set the i/o is compared to
     #define MCP_INTCONB 0X14  //same bit in defval reg 
     #define MCP_IOCONA 0x05   //config register f.7=bank, f.3=HAEN (address enable)
     #define MCP_IOCONB 0x15
     #define MCP_GPPUA 0x06    //gpio pull up 100k resistor on input pin 1=pull up enable
     #define MCP_GPPUB 0x16
     #define MCP_INTFA 0x07    //int flag register indicates if it has been enable via GPINTEN reg
     #define MCP_INTFB 0x17    //read only 1=pin cause interrupt
     #define MCP_INTCAPA 0x08  //interrupt caputre gpio value at time int occured read only, remain 
     #define MCP_INTCAPB 0x18  //unchange until clead via read intcap or gpio
     #define MCP_GPIOA 0x09    //read from this register reads port, writing modifies OLAT
     #define MCP_GPIOB 0x19
     #define MCP_OLATA 0x0A    //reads olat not port itself, write modifies the outputs
     #define MCP_OLATB 0x1A

//************** REGISTER ADDRESSES ******************************
//**************** IOCON.BANK = 0 ********************************
     #define BANK0_IOCON 0x0A   //BANK 0 USE AFTER RESET  

const unsigned int ad5453_array[100] = //logrithmic volume table
      { 0x0000, 0x0003, 0x0009, 0x0010, 0x0034, 0x0049, 0x004E, 0x0052,
        0X0057, 0x005C, 0x0062, 0x0067, 0x006E, 0x0074, 0x007B, 0x0082,
        0x008A, 0x0092, 0x009B, 0x00A4, 0x00AE, 0x00B8, 0x00C3, 0x00CE,
        0x00DA, 0x00E7, 0x00F5, 0x0104, 0x0113, 0x0123, 0x0135, 0x0147,
        0x015A, 0x016F, 0x0185, 0x019C, 0x01B4, 0x01CE, 0x01E9, 0x0206,
        0x0225, 0x0245, 0x0268, 0x028C, 0x02B3, 0x02DC, 0x0307, 0x0335,
        0x0366, 0x0399, 0x03D0, 0x040A, 0x0447, 0x0488, 0x04CD, 0x0515,
        0x0563, 0x05B4, 0x060B, 0x0666, 0x06C7, 0x072E, 0x072B, 0x080F,
        0x0889, 0x090A, 0x0993, 0x0A25, 0x0ABF, 0x0B62, 0x0C03, 0x0CC5,
        0x0B87, 0x0E54, 0x0F2D, 0x1013, 0x1107, 0x120A, 0x131B, 0x143D,
        0x1570, 0x16B5, 0x180E, 0x197B, 0x1AFD, 0x1C96, 0x1E48, 0x2013,
        0x21FA, 0x23FD, 0x261F, 0x2862, 0x2AC6, 0x2D4F, 0x2FFE, 0x32D6,
        0x35D9, 0x390A, 0x3C6B, 0x3FFF  };   //           
     
     char volume_str[4];
     char spi_cnt, read_cnt, spi_byte_in, high_byte,low_byte;
     int out_16bits;
//******************** SPI_IN *****************************************
int SPI_IN() {
    
     read_cnt=0;
     SPI_CLK=0;
     while(read_cnt<8) {                
          SPI_CLK=1;
          if(SPI_SDI==1) spi_byte_in.F0=1;
          if(SPI_SDI==0) spi_byte_in.F0=0;          
          SPI_CLK=0;    
          if(read_cnt<7) spi_byte_in<<=1; //shift data to left by 1 until first bit read reaches MSB
                 
          read_cnt++; 
    }//end while   
     
    return spi_byte_in;
}
//******************** SPI_OUT_LOW2HIGH **********************************
void SPI_OUT_LOW2HIGH(char spi_byte) {  //clock data in on rising edge
      
     spi_cnt=0;
     while(spi_cnt<8)
     {
          
          SPI_CLK=0;          
          if(spi_byte.F7==1) SPI_SDO=1;     //test msb and set output accordingly
          if(spi_byte.F7==0) SPI_SDO=0;       
          SPI_CLK=1;          
          spi_byte<<=1; //shift data to left by one
          spi_cnt++;
     }
         
}
//************************ SPI_OUT_HIGH2LOW **********************************
void SPI_OUT_HIGH2LOW(char ad5453_byte) {  //clock data on falling edge
 spi_cnt=0;    
    
     while(spi_cnt<8)
     {
          SPI_CLK=1;
          if(ad5453_byte.F7==1) SPI_SDO=1;
          if(ad5453_byte.F7==0) SPI_SDO=0;
          SPI_CLK=0;
          ad5453_byte<<=1; //shift data to left by one
          spi_cnt++;
     }
}


//****************** MCP2317_WRITE***************************************
void MCP2317_WRITE(char address, char spi_data) {
     
     MCP2317_EN=0;
     SPI_OUT_LOW2HIGH(MCP_OPCODE_WRITE);         //io config
     SPI_OUT_LOW2HIGH(address);
     SPI_OUT_LOW2HIGH(spi_data);
     MCP2317_EN=1;  

}

//*************************MCP2317_READ***************************************
int MCP2317_READ(char address_read) {
     
     MCP2317_EN=0;
     SPI_OUT_LOW2HIGH(MCP_OPCODE_READ);         //io config
     SPI_OUT_LOW2HIGH(address_read);
     SPI_IN();
     MCP2317_EN=1;
     return spi_byte_in; 

}


//********************* AD5453_OUT ************************************
void AD5453_OUT(char volume_out) {
    
     out_16bits = ad5453_array[volume_out]; //convert array value to int
     low_byte=out_16bits;                //extract low byte
     high_byte=out_16bits>>=8;           //extract hig byte
  
     high_byte=high_byte&0b00111111;    // mask bits 15&14 (control for AD5453) clock on falling edge
     AD5453_LEN=0;
     AD5453_REN=0;
     SPI_OUT_LOW2HIGH(high_byte);
     SPI_OUT_LOW2HIGH(low_byte);     

     AD5453_LEN=1;
     AD5453_REN=1;

}
//********************AD_SPI_HIGH2LOW**************************
void AD5453_OUT_CONFIG_LOWTOHIGH() { //config ad5453 to clock
                                     //data on rising edge
   
     AD5453_LEN=0;                //load default state (clk high to low)
     AD5453_REN=0;
     SPI_OUT_HIGH2LOW(0b00000000);
     SPI_OUT_HIGH2LOW(0x00);  
     AD5453_LEN=1;
     AD5453_REN=1;
     delay_us(1);
     
     AD5453_LEN=0;
     AD5453_REN=0;
     SPI_OUT_HIGH2LOW(0b11000000);       //send control bits to 
     SPI_OUT_HIGH2LOW(0x00);             //clock on low to high
     AD5453_LEN=1;
     AD5453_REN=1;
     delay_us(1);

     AD5453_LEN=0;
     AD5453_REN=0;
     SPI_OUT_HIGH2LOW(0b00000000);      //clk in new control byte 
     SPI_OUT_HIGH2LOW(0x00);            //using high to low clock
     AD5453_LEN=1;
     AD5453_REN=1;
     delay_us(1);
     
     AD5453_LEN=0;
     AD5453_REN=0;
     SPI_OUT_LOW2HIGH(0b00000000);    //clk in data low2high as 0x00
     SPI_OUT_LOW2HIGH(0x00);
     AD5453_LEN=1;
     AD5453_REN=1;
}
//***********************CONFIG SPI*********************************************
//******************************************************************************
void CONFIG_SPI() {

     AD5453_LEN=1;
     AD5453_REN=1;
     MCP2317_EN=1;
     SPI_CLK = 0;                    
     MCP_RESET = 1;     
     MCP_RESET = 0;   //reset MCP device
     delay_ms(1);
     MCP_RESET = 1;
      
     MCP2317_WRITE(BANK0_IOCON,0b10101000); //seperate port a and b hpen enable(address)

     MCP2317_WRITE(MCP_IODIRA,0x00);  //port a outputs
     MCP2317_WRITE(MCP_OLATA,0xFF);   //turn all port a on
     
     MCP2317_WRITE(MCP_IODIRB,0b1100011);  // port b inputs 
     MCP2317_WRITE(MCP_GPINTENB,0b11000011); //set interrupt on change
     MCP2317_WRITE(MCP_DEFVALB,0xFF); //pull up resistor used
     //MCP2317_WRITE(MCP_DEFVALB,0x00); //pull down resistor used
     MCP2317_WRITE(MCP_INTCONB,0xFF); //compare to defval register
     //MCP2317_WRITE(MCP_INTCONB,0x00); //compare to previous value       

     AD5453_OUT_CONFIG_LOWTOHIGH();
     AD5453_OUT(0x00);

}//end config_spi
PICFlash2, PIC16f877a, 18F4550, PIC16F883, PIC16F72. Electronics Tech trying hard to be a programmer...

zdavesf
Posts: 43
Joined: 10 May 2007 03:52

#2 Post by zdavesf » 06 Jan 2010 09:37

so i just tried replacing all my routines with the soft spi mikroc routines. just tried bare bones toggling between 2 output pins on the MCP23s17 with a 400ms delay. result.... same as with my routines the leds alternate 12 times and then stop. if i set the delay to 800ms the leds only alternate 6 times. so why is my spi crapping out after approximately 3seconds after bootup? it keeps sending the 3bytes (i can see on the scope) but the mcp is not responding to it.

here is the exact code i just tried, if anyone is board and want's to try i am using a pic18F4550, with 4MHz resonator. my config bits/fuses are set as follows (which i assume are correct). I have a scope if anyone has any ideas... i doubt its the MCP23s17 fault (i never blame ic's...)but i have new ones from digikey coming in 24 hours anyways. thanks again for any suggestions

Dave

96mhz pll =no divide (4mhz input)
cpu system clock=[osc1/osc2 Src:/1][96mhz pll src:/2}
full speed usb=clock src from 96pll/2
oscilator HS: HS+PLL,usb-HS

Code: Select all


#define HPENC_A       PORTB.F1
#define HPENC_B       PORTB.F2
#define LED1          LATB.F6


     #define SPI_SDO       LATC.F7
     #define SPI_CLK       LATC.F6
     #define SPI_SDI       PORTC.F2
     #define MCP2317_EN    LATC.F1
     #define MCP_RESET     LATC.F0
     #define MCP_INTB      PORTB.F5

     #define MCP_OPCODE_WRITE 0b01001110 // hpen enabled
     #define MCP_OPCODE_READ  0b01001111

//************** REGISTER ADDRESSES ******************************
//**************** IOCON.BANK = 1 ********************************

     #define MCP_IODIRA 0x00
     #define MCP_IODIRB 0x10
     #define MCP_IPOLA 0x01    //input polarity, 1=GPIO register bit will reflect
     #define MCP_IPOLB 0x11    //opposite logic of input, 0 will be the same
     #define MCP_GPINTENA 0x02 //interrupt on change, defval and intcon register must be altered
     #define MCP_GPINTENB 0x12 //1= enable interrupt on change, 0 disable
     #define MCP_DEFVALA 0x03  //enabled via GPINTEN and INTCON, oppostite value on pin will
     #define MCP_DEFVALB 0X13  //cause interrupt to occur, these bits set the value to compare, set as pull up/down value
     #define MCP_INTCONA 0X04  //interrupt control register if bit is set the i/o is compared to
     #define MCP_INTCONB 0X14  //same bit in defval reg
     #define MCP_IOCONA 0x05   //config register f.7=bank, f.3=HAEN (address enable)
     #define MCP_IOCONB 0x15
     #define MCP_GPPUA 0x06    //gpio pull up 100k resistor on input pin 1=pull up enable
     #define MCP_GPPUB 0x16
     #define MCP_INTFA 0x07    //int flag register indicates if it has been enable via GPINTEN reg
     #define MCP_INTFB 0x17    //read only 1=pin cause interrupt
     #define MCP_INTCAPA 0x08  //interrupt caputre gpio value at time int occured read only, remain
     #define MCP_INTCAPB 0x18  //unchange until clead via read intcap or gpio
     #define MCP_GPIOA 0x09    //read from this register reads port, writing modifies OLAT
     #define MCP_GPIOB 0x19
     #define MCP_OLATA 0x0A    //reads olat not port itself, write modifies the outputs
     #define MCP_OLATB 0x1A

//************** REGISTER ADDRESSES ******************************
//**************** IOCON.BANK = 0 ********************************
     #define BANK0_IOCON 0x0A   //BANK 0 USE AFTER RESET

sbit Chip_Select at RC1_bit;
sbit SoftSpi_CLK at RC6_bit;
sbit SoftSpi_SDI at RC2_bit;
sbit SoftSpi_SDO at RC7_bit;

sbit Chip_Select_Direction at TRISC1_bit;
sbit SoftSpi_CLK_Direction at TRISC6_bit;
sbit SoftSpi_SDI_Direction at TRISC2_bit;
sbit SoftSpi_SDO_Direction at TRISC7_bit;

char data_a,button_value,spi_byte_in,x;

void SCAN_BUTTONS();
void MCP2317_WRITE(char address, char spi_data);
int MCP2317_READ(char address_read);
//**************************MAIN*********************************************
void main() {

     TRISA = 0b00000000;       // TRISX = configure i/o's
     TRISB = 0b00110111;
     TRISC = 0b00000100;
     TRISD = 0x00;
     TRISE = 0x00;

     LATA = 0b00000000;       // LATX= SET to 0 or 1
     LATB = 0b00110111;       //PORTX =test if 0 or 1
     LATC = 0b00000100;
     LATD = 0;
     LATE = 0;

     ADCON1 |= 0x0F;     // Configure all ports with analog function as digital
     ADCON0 |= 0x00;
     ADCON2 |= 0x00;
     CMCON  |= 7;        // Disable comparators

     LED1=MCP_INTB;
     data_a=0xaa;

     MCP2317_EN=1;
     SPI_CLK = 0;
     MCP_RESET = 1;
     MCP_RESET = 0;   //reset MCP device
     delay_ms(1);
     MCP_RESET = 1;

     MCP2317_WRITE(BANK0_IOCON,0b10101000); //seperate port a and b hpen enable(address)

     MCP2317_WRITE(MCP_IODIRB,0x00);  //port a outputs
     MCP2317_WRITE(MCP_OLATB,0xFF);   //turn all port a on
     x=1;
     while(x=1) {
               data_a=~data_a;
               MCP2317_WRITE(MCP_OLATB,data_a);
               delay_ms(400);
     } //end while(1)
}// end main

//*******************SCAN BUTTONS*******************************************
void SCAN_BUTTONS() {

     button_value = MCP2317_READ(MCP_GPIOA);   //read intcap or gpio
}
//****************** MCP2317_WRITE***************************************
void MCP2317_WRITE(char address, char spi_data) {

     MCP2317_EN=0;
     soft_spi_write(MCP_OPCODE_WRITE);         //io config
     soft_spi_write(address);
     soft_spi_write(spi_data);
     MCP2317_EN=1;
}

//*************************MCP2317_READ***************************************
int MCP2317_READ(char address_read) {

     MCP2317_EN=0;
     soft_spi_write(MCP_OPCODE_READ);         //io config
     soft_spi_write(address_read);
     spi_byte_in=soft_spi_read(0);
     MCP2317_EN=1;
     return spi_byte_in;

}
PICFlash2, PIC16f877a, 18F4550, PIC16F883, PIC16F72. Electronics Tech trying hard to be a programmer...

zdavesf
Posts: 43
Joined: 10 May 2007 03:52

#3 Post by zdavesf » 08 Jan 2010 06:35

In case anyone cares i just received some more MCP23S17's. I put a new one and ran my simple test code (using mikroC spi write) and all is working. So I guess the IC is too blame... I have a hard time blaming IC's if i know i have followed proper ESD precautions and not excessive voltage's. O well it works and i am happy, onward to make PCB's. O wait i have to determine if i am using 128x64 KSO108 or 240x64 T6963 graphic lcd's. I guess I will find out when the 240x64 T6963C arrive and Octals new updated library/Font Creator are released.

Dave

IC TO BLAME, PROBLEM SOLVED
PICFlash2, PIC16f877a, 18F4550, PIC16F883, PIC16F72. Electronics Tech trying hard to be a programmer...

Post Reply

Return to “mikroC PRO for PIC General”