Jump to content

nrheckman

EstablishedMember
  • Content Count

    5
  • Joined

  • Last visited

Community Reputation

0 Neutral

About nrheckman

  • Rank
    Newbrie
  1. Your right... I should have trimmed it down. That post is way out of hand... Honestly it's about 90% comments which nobody but me really cares about! Thanks for your thoughtful observations by the way. I made some changes and reworked it a couple times since I posted all that above but eventually gave up. I'm just using a serial bus now, which was extremely easy to set up and works for my needs.
  2. I have been going through everything I can find (Data Sheet, i2c_driver.h, MicroChip AN735 pdf) and I think I'm missing something important. I "think" i have everything set up correctly but I'm not seeing any transfer happening. If somebody knows another resource I should look at with some examples in C, or if my mistake is blatantly obvious from the code below... Please help me out? The following is just a basic program that writes some data from the master and reads it on the slave. Not trying to address the slave directly, just using the general call address (I'm just trying to test this out and wrap my head around i2c) The master and the slave share the following: 16f882_i2c.h: // Mask for I2C status bits // bit 0 BF: Buffer Full Status bit // bit 2 R/W: Read/Write bit Information (I2C mode only) // bit 3 S: START bit // bit 5 D/A: Data/Address bit (I2C mode only) #define SSPSTAT_BIT_MASK 0b00101101 // init i2c_master mode void i2c_master_init() { // SSPADD: Bit Rate Control // ============================================================================ // SSPADD = ((FOSC / Bit Rate) / 4) - 1 // ((20Mhz / 1Mhz) / 4) - 1 = 4 // ((20Mhz / 100Khz) / 4) - 1 = 40 sspadd = 00101000b; // set trisc pins set_bit(trisc, 3); set_bit(trisc, 4); // SSPSTAT: SSP STATUS REGISTER // ============================================================================ // 1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) // 0 = Slew rate control enabled for high speed mode (400 kHz) clear_bit(sspstat, SMP); // CKP = 0: // 1 = Data transmitted on rising edge of SCK // 0 = Data transmitted on falling edge of SCK // CKP = 1: // 1 = Data transmitted on falling edge of SCK // 0 = Data transmitted on rising edge of SCK clear_bit(sspstat, CKP); // SSPCON: SSP CONTROL REGISTER 1 // ============================================================================ // WCOL: Write Collision Detect bit // Master mode: // 1 = A write to the SSPBUF register was attempted while the I2C conditions were not valid for a transmission to be started // 0 = No collision clear_bit(sspcon, WCOL); // SSPOV: Receive Overflow Indicator bit // 1 = A byte is received while the SSPBUF register is still holding the previous byte. SSPOV is a “don’t care” in Transmit // mode (must be cleared in software). // 0 = No overflow clear_bit(sspcon, SSPOV); // SSPEN: Synchronous Serial Port Enable bit // 1 = Enables the serial port and configures the SDA and SCL pins as the source of the serial port pins // 0 = Disables serial port and configures these pins as I/O port pins set_bit(sspcon, SSPEN); // CKP: Clock Polarity Select bit // Unused in this mode clear_bit(sspcon, CKP); // SSPM<3:0>: Synchronous Serial Port Mode Select bits // 1000 = I2C Master mode, clock = FOSC / (4 * (SSPADD+1)) // 1011 = I2C firmware controlled Master mode (Slave idle) set_bit(sspcon, SSPM3); clear_bit(sspcon, SSPM2); clear_bit(sspcon, SSPM1); clear_bit(sspcon, SSPM0); // SSPCON2: SSP CONTROL REGISTER 2 // ============================================================================ // GCEN: General Call Enable bit (in I2C Slave mode only) clear_bit(sspcon2, GCEN); // ACKDT: Acknowledge Data bit (in I2C Master mode only) // In Master Receive mode: // Value transmitted when the user initiates an Acknowledge sequence at the end of a receive // 1 = Not Acknowledge // 0 = Acknowledge clear_bit(sspcon2, ACKDT); // ACKEN: Acknowledge Sequence Enable bit (in I2C Master mode only) // In Master Receive mode: // 1 = Initiate Acknowledge sequence on SDA and SCL pins, and transmit ACKDT data bit. // Automatically cleared by hardware. // 0 = Acknowledge sequence idle clear_bit(sspcon2, ACKEN); // RCEN: Receive Enable bit (in I2C Master mode only) // 1 = Enables Receive mode for I2C // 0 = Receive idle clear_bit(sspcon2, RCEN); // PEN: Stop Condition Enable bit (in I2C Master mode only) // SCK Release Control: // 1 = Initiate Stop condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Stop condition Idle clear_bit(sspcon2, PEN); // RSEN: Repeated Start Condition Enabled bit (in I2C Master mode only) // 1 = Initiate Repeated Start condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Repeated Start condition Idle clear_bit(sspcon2, RSEN); // SEN: Start Condition Enabled bit (in I2C Master mode only) // In Master mode: // 1 = Initiate Start condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Start condition Idle clear_bit(sspcon2, SEN); } // init i2c_slave init void i2c_slave_init(char addr) { sspadd = addr; // set trisc pins set_bit(trisc, 3); set_bit(trisc, 4); // SSPSTAT: SSP STATUS REGISTER // ============================================================================ // 1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) // 0 = Slew rate control enabled for high speed mode (400 kHz) set_bit(sspstat, SMP); // CKP = 0: // 1 = Data transmitted on rising edge of SCK // 0 = Data transmitted on falling edge of SCK // CKP = 1: // 1 = Data transmitted on falling edge of SCK // 0 = Data transmitted on rising edge of SCK clear_bit(sspstat, CKP); // SSPCON: SSP CONTROL REGISTER 1 // ============================================================================ // WCOL: Write Collision Detect bit // Master mode: // 1 = A write to the SSPBUF register was attempted while the I2C conditions were not valid for a transmission to be started // 0 = No collision clear_bit(sspcon, WCOL); // SSPOV: Receive Overflow Indicator bit // 1 = A byte is received while the SSPBUF register is still holding the previous byte. SSPOV is a “don’t care” in Transmit // mode (must be cleared in software). // 0 = No overflow clear_bit(sspcon, SSPOV); // SSPEN: Synchronous Serial Port Enable bit // 1 = Enables the serial port and configures the SDA and SCL pins as the source of the serial port pins // 0 = Disables serial port and configures these pins as I/O port pins set_bit(sspcon, SSPEN); // CKP: Clock Polarity Select bit // Unused in this mode clear_bit(sspcon, CKP); // SSPM<3:0>: Synchronous Serial Port Mode Select bits // 0110 = I2C Slave mode, 7-bit address // 0111 = I2C Slave mode, 10-bit address // 1110 = I2C Slave mode, 7-bit address with Start and Stop bit interrupts enabled // 1111 = I2C Slave mode, 10-bit address with Start and Stop bit interrupts enabled clear_bit(sspcon, SSPM3); set_bit(sspcon, SSPM2); set_bit(sspcon, SSPM1); clear_bit(sspcon, SSPM0); // SSPCON2: SSP CONTROL REGISTER 2 // ============================================================================ // GCEN: General Call Enable bit (in I2C Slave mode only) // 1 = Enable interrupt when a general call address (0000h) is received in the SSPSR // 0 = General call address disabled set_bit(sspcon2, GCEN); // ACKDT: Acknowledge Data bit (in I2C Master mode only) // In Master Receive mode: // Value transmitted when the user initiates an Acknowledge sequence at the end of a receive // 1 = Not Acknowledge // 0 = Acknowledge clear_bit(sspcon2, ACKDT); // ACKEN: Acknowledge Sequence Enable bit (in I2C Master mode only) // In Master Receive mode: // 1 = Initiate Acknowledge sequence on SDA and SCL pins, and transmit ACKDT data bit. // Automatically cleared by hardware. // 0 = Acknowledge sequence idle clear_bit(sspcon2, ACKEN); // RCEN: Receive Enable bit (in I2C Master mode only) // 1 = Enables Receive mode for I2C // 0 = Receive idle clear_bit(sspcon2, RCEN); // PEN: Stop Condition Enable bit (in I2C Master mode only) // SCK Release Control: // 1 = Initiate Stop condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Stop condition Idle clear_bit(sspcon2, PEN); // RSEN: Repeated Start Condition Enabled bit (in I2C Master mode only) // 1 = Initiate Repeated Start condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Repeated Start condition Idle clear_bit(sspcon2, RSEN); // SEN: Start Condition Enabled bit (in I2C Master mode only) // In Master mode: // 1 = Initiate Start condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Start condition Idle clear_bit(sspcon2, SEN); } void i2c_start() { // SEN: Start Condition Enabled bit (in I2C Master mode only) // In Master mode: // 1 = Initiate Start condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Start condition Idle set_bit(sspcon2, SEN); // wait for start condition to complete while (test_bit(sspcon2, SEN)) {} } void i2c_stop() { // PEN: Stop Condition Enable bit (in I2C Master mode only) // SCK Release Control: // 1 = Initiate Stop condition on SDA and SCL pins. Automatically cleared by hardware. // 0 = Stop condition Idle set_bit(sspcon2, PEN); // wait for stop condition to complete while (test_bit(sspcon2, PEN)) {} } void i2c_write_data(char c) { sspbuf = c; // SSPSTAT: SSP STATUS REGISTER // BF: Buffer Full Status bit // 1 = Data transmit in progress (does not include the ACK and Stop bits), SSPBUF is full // 0 = Data transmit complete (does not include the ACK and Stop bits), SSPBUF is empty while (test_bit(sspstat, BF)) {} } void i2c_write_addr(char c) { // set write bit on address set_bit(c, 7); sspbuf = c; // SSPSTAT: SSP STATUS REGISTER // BF: Buffer Full Status bit // 1 = Data transmit in progress (does not include the ACK and Stop bits), SSPBUF is full // 0 = Data transmit complete (does not include the ACK and Stop bits), SSPBUF is empty while (test_bit(sspstat, BF)) {} } char i2c_read() { return sspbuf; // Reset the SSPIF interrupt flag clear_bit( pir1, SSPIF ); } bool i2c_is_data_ready() { // is there an SSP interupt? if (test_bit(pir1, SSPIF)) { char i2c_data = 0; // Test if we have an overflow condition and clear it if (test_bit( sspcon, SSPOV )) { // Do a dummy read of the SSPBUF i2c_data = sspbuf; // Clear the overflow flag clear_bit( sspcon, SSPOV ); } else { // determin the ssp status char i2c_status = 0; // Mask the status bits out from the other unimportant register bits i2c_status = ( sspstat & SSPSTAT_BIT_MASK ); // SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1 // Master Write, Last Byte was an Address if ((i2c_status ^ 0b00001001 ) == 0) { // do a dummy read i2c_data = sspbuf; // Reset the SSPIF interrupt flag clear_bit( pir1, SSPIF ); // Master Write, Last Byte was Data } else if ((i2c_status ^ 0b00101001 ) == 0) { return true; // Master Read, Last Byte was an Address } else if ((i2c_status ^ 0b00001100 ) == 0) { // do a dummy read i2c_data = sspbuf; // TODO: implement me // Reset the SSPIF interrupt flag clear_bit( pir1, SSPIF ); // Master Read, Last Byte was Data } else if ((i2c_status ^ 0b00101100 ) == 0) { // do a dummy read i2c_data = sspbuf; // TODO: implement me // Reset the SSPIF interrupt flag clear_bit( pir1, SSPIF ); // Master NACK } else if ((i2c_status ^ 0b00101000 ) == 0) { // do a dummy read i2c_data = sspbuf; // TODO: implement me // Reset the SSPIF interrupt flag clear_bit( pir1, SSPIF ); } } } } This is the master main program. i2cmaster_test.c: ##include <system.h> #include "../16f882_i2c.h" #include "../serial.h" #pragma CLOCK_FREQ 20000000 #pragma DATA _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & \ _BOR_ON & _CPD_OFF & _CP_OFF & _PWRTE_OFF \ & _MCLRE_OFF & _HS_OSC #pragma DATA _CONFIG2, _WRT_OFF & _BOR40V void main() { // disable analog on porta ansel = 0; // char buffers char porta_buf = 0; // outputs trisa = porta_buf; // serial serial_init(); // I2C Communications i2c_master_init(); delay_ms(1000); puts("Ready"); puts_newline(); puts_newline(); while(1) { set_bit(porta_buf, 0); porta = porta_buf; puts("SSPSTAT: "); puts_byte(sspstat); puts('\t'); puts("SSPCON: "); puts_byte(sspcon); puts('\t'); puts("SSPCON2: "); puts_byte(sspcon2); puts('\t'); puts("SSPADD: "); puts_byte(sspadd); puts('\t'); puts("PIR1: "); puts_byte(pir1); puts_newline(); // start i2c_start(); // write addr i2c_write_addr(00000000b); // write data i2c_write_data(11111111b); // stop i2c_stop(); clear_bit(porta_buf, 0); porta = porta_buf; delay_ms(1000); } } This is the slave main program i2cslave_test.c: #include <system.h> #include "../16f882_i2c.h" #include "../serial.h" #pragma CLOCK_FREQ 20000000 #pragma DATA _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & \ _BOR_ON & _CPD_OFF & _CP_OFF & _PWRTE_OFF & _WDT_OFF & _MCLRE_OFF & _HS_OSC #pragma DATA _CONFIG2, _WRT_OFF & _BOR40V void main() { char data = 0; serial_init(); i2c_slave_init(00000010b); delay_ms(500); puts("Ready"); puts_newline(); while (1) { puts("SSPSTAT: "); puts_byte(sspstat); puts('\t'); puts("SSPCON: "); puts_byte(sspcon); puts('\t'); puts("SSPCON2: "); puts_byte(sspcon2); puts('\t'); puts("SSPADD: "); puts_byte(sspadd); puts('\t'); puts("PIR1: "); puts_byte(pir1); puts_newline(); if (i2c_is_data_ready()) { data = i2c_read(); puts_newline(); puts_newline(); puts("got data: "); puts_byte(data); puts_newline(); puts_newline(); } delay_ms(10); } } Incase it's helpful, this is my serial library serial.h: void serial_init() { // reg 7 6 5 4 3 2 1 0 // BAUDCTL ABDOVF RCIDL ? SCKP BRG16 ? WUE ABDEN // INTCON GIE PEIE T0IE INTE RBIE T0IF INTF RBIF // PIE1 ? ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1I // PIR1 ? ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF // RCREG EUSART Receive Data Register // RCSTA SPEN RX9 SREN CREN ADDEN FERR OERR RX9D // SPBRG BRG7 BRG6 BRG5 BRG4 BRG3 BRG2 BRG1 BRG0 // SPBRGH BRG15 BRG14 BRG13 BRG12 BRG11 BRG10 BRG9 BRG8 // TRISC TRISC7 TRISC6 TRISC5 TRISC4 TRISC3 TRISC2 TRISC1 TRISC0 // TXREG EUSART Transmit Data Register // TXSTA CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D //enable the transmiter & receiver for async txsta.TXEN = 1; rcsta.CREN = 1; txsta.SYNC = 0; rcsta.SPEN = 1; // FOSC = 20.000 MHz // SYNC = 0, BRGH = 1, BRG16 = 1 or SYNC = 1, BRG16 = 1 // rate actual error SPBRG // 9600 9597 -0.03 520 // 19.2k 19.23k 0.16 259 // 57.6k 57.47k -0.22 86 // 115.2k 116.3k 0.94 42 txsta.BRGH = 1; baudctl.BRG16 = 1; spbrg = 42; spbrgh = 0; } void serial_write(char c) { while (!pir1.TXIF); txreg = c; } char serial_read () { while (!pir1.RCIF); return rcreg; } void gets(char *destination) { while ((*destination++ = serial_read()) != 0x0d); // wait until tx register is empty *--destination = 0; } void puts(char *source) { while (*source != 0) // wait until tx register is empty serial_write(*source++); } void puts(char *sourcea, char *sourceb) { while (*sourcea != 0) // wait until tx register is empty serial_write(*sourcea++); while (*sourceb != 0) // wait until tx register is empty serial_write(*sourceb++); } void puts(char source) { serial_write(source); } void puts_byte(char source) { if (test_bit(source,7)) { puts("1"); } else { puts("0"); } if (test_bit(source,6)) { puts("1"); } else { puts("0"); } if (test_bit(source,5)) { puts("1"); } else { puts("0"); } if (test_bit(source,4)) { puts("1"); } else { puts("0"); } if (test_bit(source,3)) { puts("1"); } else { puts("0"); } if (test_bit(source,2)) { puts("1"); } else { puts("0"); } if (test_bit(source,1)) { puts("1"); } else { puts("0"); } if (test_bit(source,0)) { puts("1"); } else { puts("0"); } } void puts_newline() { serial_write(0x0d); serial_write(0x0a); }
  3. That is definitely what I was missing. I guess I missed the part where it said that defaulted to on. Thank you for pointing out my mistake!
  4. That was just what I was missing. I guess I read the datasheet wrong and thought analog was disabled by default. Thank you for pointing out my mistake!
  5. I have been trying to turn on the weak pull-up feature of portb on a pic16f882 but can't seem to get it to work. I have been working my way through the options learning about PIC microcontrollers but I'm no expert... Here is some sample code I have been trying to make work: #include <system.h> #include <stdlib.h> #pragma CLOCK_FREQ 8000000 #pragma DATA _CONFIG1, _LVP_OFF & _FCMEN_OFF \ & _IESO_OFF & _BOR_OFF & _CPD_OFF \ & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF \ & _WDT_OFF & _INTRC_OSC_NOCLKOUT \ & _EXTRC_OSC_NOCLKOUT & _INTOSC #pragma DATA _CONFIG2, _WRT_OFF & _BOR40V void main() { char porta_buf, portb_buf = 0; //set outputs porta = trisa = 0; // set inputs (jumpers) set_bit(portb_buf, 2); set_bit(portb_buf, 3); set_bit(portb_buf, 4); set_bit(portb_buf, 5); portb = trisb = portb_buf; // enable pull up on portb inputs option_reg.7 = 0; wpub.2 = 1; wpub.3 = 1; wpub.4 = 1; wpub.5 = 1; // startup delay delay_ms(5000); // main program loop while (1) { porta_buf = 0; if (!portb.2) { set_bit(porta_buf, 5); } if (!portb.3) { set_bit(porta_buf, 4); } if (!portb.4) { set_bit(porta_buf, 3); } if (!portb.5) { set_bit(porta_buf, 2); } // set pins porta = porta_buf; } } What I'm observing is that the input pins on portb are always low. When I break out the voltmeter and check the pins, there isn't any voltage on them. Maybe I misunderstood the purpose of enabling the pull-up on the input pins. I thought I could turn it on and thus, avoid adding pull-up resistors in hardware? Or, I have made an error in my above code. Either is a likely possibility... Anybody see my mistake?
×
×
  • Create New...