I2C AVR GCC Library - Page 1
Forum section: electronics / general

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 12, 2013, 10:14:28 pm
content: helloi am building a library for my atmega328p its to allow all 4 communication methods over i2c (MT,MR,ST and SR)now i think i have gotten the MT and MR modes done but i am unsure about the ST and SR for several reasons.1, what do i have to initialise so that it acknowledges its own lave address? (do i just enable the TWEA bit in the TWCR register when i set its slave address?2, what sort of interrupt is needed so that when i do receive data i can read it from the register and store it in a bufferand i believe there are a few other problems as-well. i would have a look at an already made I2C library but i can only find MT and MR ones :/here is the current library it allows initialisation and setting a slave address, sending the start, rep start and stop commands and allows for reading and writing data over the I2C bus i just need to get it so it is able to read and write in slave mode:Code:/** Carbonwire.c** Created: 12/09/2013 21:25:36* Author: carbon dude oxide*/#include <avr/io.h>#include <util/twi.h>#include "Carbonwire.h"static volatile uint8_t twi_state; //the current TWI state (MT,MS,RT,RS and ready)int function(void){//TODO:: Please write your application codereturn 0;}void twi_begin(void) //initiate the TWI{twi_state = TWI_READY; //set the state as readyPORTC = (1 << PORTC5) | (1 << PORTC4); //turn on internal pull ups on SDA and SCL linesTWSR = 0; //ensure no prescalerTWBR = ((F_CPU / TWI_FREQ) - 16) / 2; //calculate TWI clock speed register (from data sheet)}void twi_setAddress(uint8_t address) //set a slave address for ATMega328{TWAR = (address << 1); //set the address in the upper bits and leave general call off (Right Most Bit)//TWCR = (1 << TWEA) //enable slave ack//TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWIE); //enable the TWI and allow interrupts and acks}uint8_t twi_start(uint8_t address) //send the address byte and{uint8_t twscb; //create TWI Status Check ByteTWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); //send start conditionwhile(!(TWCR & (1 << TWINT))); //wait until start transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TW_START) && (twscb != TW_REP_START)) return 1; //if the status is not start or repeated start return 1 (error)TWDR = address; //load the address into TWDRTWCR = (1 << TWINT) | (1 << TWEN); //enable TWI interrupts and send the address packet (via enabling)while(!(TWCR & (1 << TWINT))); // wait until ack/nack has been receivedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TW_MT_SLA_ACK) && (twscb != TW_MR_SLA_ACK) ) return 1; //if the status is not master transmit ack or master receive ack then return 1 (error)switch (twscb){case TW_MT_SLA_ACK: twi_state = TWI_MT; //set status to MT if in MT modecase TW_MR_SLA_ACK: twi_state = TWI_MR; //set status to MR if in MR mode}return 0; //slave device has acknowledged and is ready to read/write data}uint8_t twi_repeatstart(uint8_t address){return twi_start(address); //call the twi_start() function and return its value}uint8_t twi_write(uint8_t wdata){if (twi_state != TWI_MT) return 1; //if the device is not in MT mode then it cannot write so return 1 (error)uint8_t twscb; //create TWI Status Check ByteTWDR = wdata; //load data into the registerTWCR = (1<<TWINT) | (1<<TWEN); //send the data packet stored in the registerwhile(!(TWCR & (1 << TWINT))); //wait until transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif(twscb != TW_MT_DATA_ACK) return 1; //if the device has not returned an ack bit then return 1 (error)return 0; //slave device has acknowledged the sent data packet}uint8_t twi_read(uint8_t ret) //read a byte from the slave device and return an ack/nack (ret value 1/0){if (twi_state != TWI_MR) return 1; //if the device is not in MR mode then it cannot read so return 1 (error)switch (ret){case 0: TWCR = (1<<TWINT) | (1<<TWEN); //if ret is 0 send a nack byte back after readingcase 1: TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //if ret is 1 send a ack byte back after reading}while(!(TWCR & (1 << TWINT))); //wait for transmission to completereturn TWDR; // return the data that was just received from slave}void twi_stop(void){TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); //send the stop conditionwhile(TWCR & (1 << TWSTO)); // wait until top condition has been transmittedtwi_state = TWI_READY; //set internal status back to ready}

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 12, 2013, 10:20:52 pm
content: ah, i have just found the application note for using it as an I2C slave.if you know please still commend but i am going to have a look though the app note now

author: dannyf
author_rank: Super Contributor
timestamp: September 12, 2013, 10:36:36 pm
content: QuoteSet up the module as a receiver and specify its slave address. Enable interrupt and when a valid slave address is received from the bus, you jump to the isr.QuoteYou will need to process the various status bits (based on what's being received) in the twi isr.Read the datasheet or you stand no chance.

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 12, 2013, 10:55:31 pm
content: i have the data sheet out but i am having trouble finding the interupt for when the device receives a SLA+RWim going to ask that at the bottom of the library can i call the ISR() directly? and is the vector for data TWI_vect? in the app note it calles the ISR like this:Code:#pragma vector=TWI_vect__interrupt void TWI_ISR( void ){and then it uses a switch command to check all the status codes and what to do with them. i am unsure however how this calles the ISR with the right vector unfortunatly

author: dannyf
author_rank: Super Contributor
timestamp: September 12, 2013, 10:59:33 pm
content: QuoteIf you have an IAR-AVR.Otherwise, read the manual for your compiler.

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 12, 2013, 11:17:36 pm
content: kk il have a look nowi believe im using GCC-AVR in atmel studio

author: Kremmen
author_rank: Super Contributor
timestamp: September 13, 2013, 07:00:59 am
content: Then the interrupt vectors are listed in avr.libc documentation athttp://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 13, 2013, 12:18:58 pm
content: ok i think i have now finished the MT, MR and SR modes i am unsure about a couple of things (mainly error handling and making the code a bit more efficiant) here is the current code:Code:/** CWire.c** Created: 12/09/2013 21:25:36* Author: carbon dude oxide*/#include <avr/io.h>#include <avr/interrupt.h>#include "CWire.h"static uint8_t twi_state; //the current TWI state (MT,MS,RT,RS and ready)static uint8_t twi_slave; //the current mode (0 for master, 1 for slave)//receiving bufferstatic uint8_t twi_rxbuffer; //TWI rx bufferstatic uint8_t twi_rxptr;static uint8_t twi_rxbib; //bytes in buffer//transmitting bufferstatic uint8_t twi_txbuffer; //TWI tx bufferstatic uint8_t twi_txptr;static uint8_t twi_txbib; //bytes in buffervoid twi_begin(void) //initiate the TWI{twi_flush(); //empty buffers (just in case)twi_state = TWI_READY; //set the state as readyPORTC = (1 << PORTC5) | (1 << PORTC4); //turn on internal pull ups on SDA and SCL linesTWSR = 0; //ensure no prescalerTWBR = ((F_CPU / TWI_FREQ) - 16) / 2; //calculate TWI clock speed register (from data sheet)TWCR = (1 << TWEN); //enable the I2C bustwi_slave = 0; //set into master mode}void twi_setAddress(uint8_t address) //set a slave address for ATMega328 and set into slave mode{TWAR = (address << 1); //set the address in the upper bits and leave general call off (Right Most Bit)TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //enable TWI and interrupts and accept incoming save addresses.twi_slave = 1; //set into slave mode}uint8_t twi_start(uint8_t address) //send the address byte and{twi_flush(); //empty buffersuint8_t twscb; //create TWI Status Check ByteTWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (0 << TWEA) | (0 << TWIE); //go to master mode and send start condition (disable slave ack if active)while(!(TWCR & (1 << TWINT))); //wait until start transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TWI_START) && (twscb != TWI_REP_START)) return 1; //if the status is not start or repeated start return 1 (error)TWDR = address; //load the address into TWDRTWCR = (1 << TWINT) | (1 << TWEN); //enable TWI interrupts and send the address packet (via enabling)while(!(TWCR & (1 << TWINT))); // wait until ack/nack has been receivedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TWI_MT_ADR_ACK) && (twscb != TWI_MR_ADR_ACK) ) return 1; //if the status is not master transmit ack or master receive ack then return 1 (error)switch (twscb){case TWI_MT_ADR_ACK: twi_state = TWI_MT; //set status to MT if in MT modecase TWI_MR_ADR_ACK: twi_state = TWI_MR; //set status to MR if in MR mode}return 0; //slave device has acknowledged and is ready to read/write data}uint8_t twi_repeatstart(uint8_t address) //send a repeated start command on the bus{return twi_start(address); //call the twi_start() function and return its value}uint8_t twi_write(uint8_t wdata) //write wdata to the bus as long as a slave has been ack{if (twi_state != TWI_MT) return 1; //if the device is not in MT mode then it cannot write so return 1 (error)uint8_t twscb; //create TWI Status Check ByteTWDR = wdata; //load data into the registerTWCR = (1<<TWINT) | (1<<TWEN); //send the data packet stored in the registerwhile(!(TWCR & (1 << TWINT))); //wait until transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif(twscb != TWI_MT_DATA_ACK) return 1; //if the device has not returned an ack bit then return 1 (error)return 0; //slave device has acknowledged the sent data packet}uint8_t twi_read(uint8_t ret) //read a byte from the slave device and return an ack/nack (ret value 1/0){if (twi_state == TWI_MR) //if the device is in MR mode then read data from connected slave device{switch (ret){case 0: TWCR = (1<<TWINT) | (1<<TWEN); //if ret is 0 send a nack byte back after readingcase 1: TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //if ret is 1 send a ack byte back after reading}while(!(TWCR & (1 << TWINT))); //wait for transmission to completereturn TWDR; // return the data that was just received from slave}else if ((twi_state == TWI_SR) || (twi_state == TWI_READY)) //if the device is in SR mode or Ready mode then read data from rx buffer{if (twi_rxbib > 0) //check to see if there are any bytes to read in the buffer{uint8_t retbuf = twi_rxbuffer; // save the first received byte (first in first out)for (int i=1; i<TWI_BUFFER_LENGTH;i++) //move items in the buffer over 1{twi_rxbuffer[i-1] = twi_rxbuffer;}twi_rxbuffer[((int)TWI_BUFFER_LENGTH)-1] = 0; //empty the last byte in the bufferreturn retbuf; //return the saved buffer (oldest data / first to arrive byte)}else{return 1; //return an error as there are no byte to read in buffer}}return 1; //if in any other mode return 1 (error)}void twi_stop(void){TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); //send the stop conditionwhile(TWCR & (1 << TWSTO)); // wait until top condition has been transmittedtwi_state = TWI_READY; //set internal status back to readyswitch (twi_slave){case 0: TWCR = (1 << TWEN) | (0 << TWIE) | (0 << TWINT) | (0 << TWEA); //keep in master modecase 1: TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //set back to slave mode}}void twi_flush(void) //empties all buffers and resets pointer and byte counter values{for (int i=0; i<TWI_BUFFER_LENGTH; i++) //repeat for length of buffers{twi_rxbuffer = 0; //cycle though all buffer entries and reset to 0x00twi_txbuffer = 0; //cycle though all buffer entries and reset to 0x00}twi_rxbib = 0;twi_txbib = 0;twi_rxptr = 0;twi_txptr = 0;}uint8_t twi_available(void) //returns amount of bytes contained within the rx buffer{return (uint8_t)twi_rxbib;}uint8_t twi_peak(void) //show most recent data without removing from the rx buffer{if (twi_rxbib == 0) return 0; // if there is no stored data then returnreturn twi_rxbuffer[(twi_rxptr-1)]; //return the latest stored data}ISR(TWI_vect){switch(TWSR){//ST mode statusescase TWI_ST_ADR_ACK://own SLA+R has been received and ACK has been sent. in ST modetwi_state = TWI_ST;case TWI_ST_ADR_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returnedcase TWI_ST_DATA_ACK:// Data byte in TWDR has been transmitted; ack has been receivedcase TWI_ST_DATA_NACK:// Data byte in TWDR has been transmitted; nack has been received.case TWI_ST_DATA_ACK_LAST_BYTE:// Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received//SR mode statusescase TWI_SR_ADR_ACK:// Own SLA+W has been received ACK has been returnedtwi_state = TWI_SR;case TWI_SR_ADR_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returnedcase TWI_SR_GEN_ACK:// General call address has been received; ACK has been returnedcase TWI_SR_GEN_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returnedcase TWI_SR_ADR_DATA_ACK:// Previously addressed with own SLA+W; data has been received; ACK has been returnedtwi_rxbuffer = TWDR;//load the received data from the TWDR register into the rx buffertwi_rxptr++;//add 1 to the pointer to prevent overwritestwi_rxbib++;//add 1 to the mount of bytes in the buffercase TWI_SR_ADR_DATA_NACK:// Previously addressed with own SLA+W; data has been received; NOT ACK has been returnedtwi_rxbuffer = TWDR;//load the received data from the TWDR register into the rx buffertwi_rxptr++;//add 1 to the pointer to prevent overwritestwi_rxbib++;//add 1 to the mount of bytes in the bufferTWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //return to ready state, TWI, interrupt and ACK activetwi_state = TWI_READY;case TWI_SR_GEN_DATA_ACK:// Previously addressed with general call; data has been received; ACK has been returnedcase TWI_SR_GEN_DATA_NACK:// Previously addressed with general call; data has been received; NOT ACK has been returnedcase TWI_SR_STOP_RESTART:// A STOP condition or repeated START condition has been received while still addressed as SlaveTWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //return to ready state, TWI, interrupt and ACK activetwi_state = TWI_READY;//Miscellaneous statusescase TWI_BUS_ERROR:// Bus error due to an illegal START or STOP conditionTWCR = (1 << TWSTO) | (1 << TWINT); //reset bus by releasing SDA and SCL linesdefault: //no status code (0x00) or unknown status codeTWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //unknown status, return to ready state, TWI, interupt and ACK activetwi_state = TWI_READY;}}The read function that i have has two different modes one for when the device is in MR mode and another when the device in in its ready state or MR mode which reads data from the rxbuffer (the slave buffer) (function is twi_read() ) the part that i would like to make more efficiant is when it removes data in the buffer then shuffles everything else along in it.Code:if (twi_rxbib > 0) //check to see if there are any bytes to read in the buffer{uint8_t retbuf = twi_rxbuffer; // save the first received byte (first in first out)for (int i=1; i<TWI_BUFFER_LENGTH;i++) //move items in the buffer over 1{twi_rxbuffer[i-1] = twi_rxbuffer;}twi_rxbuffer[((int)TWI_BUFFER_LENGTH)-1] = 0; //empty the last byte in the bufferreturn retbuf; //return the saved buffer (oldest data / first to arrive byte)}so what this code currently does is saves the oldest data in the buffer (first byte that was received) and using a for loop moves everything along so rxbuffer now becomes rxbuffer and the same until the end of the buffer and then clears the last byte otherwise there would be a duplication now can I do this more efficiently as i am pretty sure there is a better way of doing this but i am unsure of what i would have to do.another part I would like a bit of help on is when the bus status goes into its various arbitration modes t i just make the atmega release the bus pins? or do i have to do some other stuff as well? and how does the arbitration recovery process differer between the avr being a master and a slave as there are different status codes for a master arbitration and slave arbitration.

author: Kremmen
author_rank: Super Contributor
timestamp: September 13, 2013, 03:11:49 pm
content: Please do remember that in your long switch statement in the ISR, you need a break; after each case, otherwise control just falls through to the next case. That is almost never the intention. In other words the case{ does not delimit anything.

author: dannyf
author_rank: Super Contributor
timestamp: September 13, 2013, 03:50:13 pm
content: It may be helpful to look into circular buffers - google linux kfifo.c.Some chips, like stm32, allows the dma to configure a fifo buffer thus receiving can be done with minimum cpu care.

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 13, 2013, 08:46:43 pm
content: Quote from: Kremmen on September 13, 2013, 03:11:49 pmthank you very much for letting me knowjust fixed that issueQuote from: dannyf on September 13, 2013, 03:50:13 pmil have a look into it nowi have made a few alterations and have also added a new function for when arbitration is lost, it resets the device into its ready state and checks to see if it in master or slave mode. if its in slave mode it re enables the interupts and ack's for SLA+R/WCode:/** CWire.c** Created: 12/09/2013 21:25:36* Author: carbon dude oxide*/#include <avr/io.h>#include <avr/interrupt.h>#include "CWire.h"static uint8_t twi_state; //the current TWI state (MT,MS,RT,RS and ready)static uint8_t twi_slave; //the current mode (0 for master, 1 for slave)//receiving bufferstatic uint8_t twi_rxbuffer; //TWI rx bufferstatic uint8_t twi_rxptr;static uint8_t twi_rxbib; //bytes in buffer//transmitting bufferstatic uint8_t twi_txbuffer; //TWI tx bufferstatic uint8_t twi_txptr;static uint8_t twi_txbib; //bytes in buffervoid twi_begin(void) //initiate the TWI{twi_flush(); //empty buffers (just in case)twi_state = TWI_READY; //set the state as readyPORTC = (1 << PORTC5) | (1 << PORTC4); //turn on internal pull ups on SDA and SCL linesTWSR = 0; //ensure no prescalerTWBR = ((F_CPU / TWI_FREQ) - 16) / 2; //calculate TWI clock speed register (from data sheet)TWCR = (1 << TWEN); //enable the I2C bustwi_slave = 0; //set into master mode}void twi_setAddress(uint8_t address) //set a slave address for ATMega328 and set into slave mode{TWAR = (address << 1); //set the address in the upper bits and leave general call off (Right Most Bit)TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //enable TWI and interrupts and accept incoming save addresses.twi_slave = 1; //set into slave mode}uint8_t twi_start(uint8_t address) //send the address byte and{twi_flush(); //empty buffersuint8_t twscb; //create TWI Status Check ByteTWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (0 << TWEA) | (0 << TWIE); //go to master mode and send start condition (disable slave ack if active)while(!(TWCR & (1 << TWINT))); //wait until start transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TWI_START) && (twscb != TWI_REP_START)) return 1; //if the status is not start or repeated start return 1 (error)TWDR = address; //load the address into TWDRTWCR = (1 << TWINT) | (1 << TWEN); //enable TWI interrupts and send the address packet (via enabling)while(!(TWCR & (1 << TWINT))); // wait until ack/nack has been receivedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif ((twscb != TWI_MT_ADR_ACK) && (twscb != TWI_MR_ADR_ACK) ) return 1; //if the status is not master transmit ack or master receive ack then return 1 (error)switch (twscb){case TWI_MT_ADR_ACK: twi_state = TWI_MT; //set status to MT if in MT modecase TWI_MR_ADR_ACK: twi_state = TWI_MR; //set status to MR if in MR mode}return 0; //slave device has acknowledged and is ready to read/write data}uint8_t twi_repeatstart(uint8_t address) //send a repeated start command on the bus{return twi_start(address); //call the twi_start() function and return its value}uint8_t twi_write(uint8_t wdata) //write wdata to the bus as long as a slave has been ack{if (twi_state != TWI_MT) return 1; //if the device is not in MT mode then it cannot write so return 1 (error)uint8_t twscb; //create TWI Status Check ByteTWDR = wdata; //load data into the registerTWCR = (1<<TWINT) | (1<<TWEN); //send the data packet stored in the registerwhile(!(TWCR & (1 << TWINT))); //wait until transmission has completedtwscb = TWSR & 0xF8; // set the TWI Status Check Byte to bits 3-7 from TWSRif(twscb != TWI_MT_DATA_ACK) return 1; //if the device has not returned an ack bit then return 1 (error)return 0; //slave device has acknowledged the sent data packet}uint8_t twi_read(uint8_t ret) //read a byte from the slave device and return an ack/nack (ret value 1/0){if (twi_state == TWI_MR) //if the device is in MR mode then read data from connected slave device{switch (ret){case 0: TWCR = (1<<TWINT) | (1<<TWEN); //if ret is 0 send a nack byte back after readingcase 1: TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //if ret is 1 send a ack byte back after reading}while(!(TWCR & (1 << TWINT))); //wait for transmission to completereturn TWDR; // return the data that was just received from slave}else if ((twi_state == TWI_SR) || (twi_state == TWI_READY)) //if the device is in SR mode or Ready mode then read data from rx buffer{if (twi_rxbib == 0) return 1; //return an error as there are no bytes to read in bufferuint8_t retbuf = twi_rxbuffer; // save the first received byte (first in first out)for (int i=1; i<TWI_BUFFER_LENGTH;i++) //move items in the buffer over 1{twi_rxbuffer[i-1] = twi_rxbuffer;}twi_rxbuffer[((int)TWI_BUFFER_LENGTH)-1] = 0; //empty the last byte in the bufferreturn retbuf; //return the saved buffer (oldest data / first to arrive byte)}return 1; //if in any other mode return 1 (error)}void twi_stop(void){TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); //send the stop conditionwhile(TWCR & (1 << TWSTO)); // wait until top condition has been transmittedtwi_state = TWI_READY; //set internal status back to readyswitch (twi_slave){case 0: TWCR = (1 << TWEN) | (0 << TWIE) | (0 << TWINT) | (0 << TWEA); //keep in master modecase 1: TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //set back to slave mode}}void twi_flush(void) //empties all buffers and resets pointer and byte counter values{for (int i=0; i<TWI_BUFFER_LENGTH; i++) //repeat for length of buffers{twi_rxbuffer = 0; //cycle though all buffer entries and reset to 0x00twi_txbuffer = 0; //cycle though all buffer entries and reset to 0x00}twi_rxbib = 0;twi_txbib = 0;twi_rxptr = 0;twi_txptr = 0;}uint8_t twi_available(void) //returns amount of bytes contained within the rx buffer{return (uint8_t)twi_rxbib;}uint8_t twi_peak(void) //show most recent data without removing from the rx buffer{if (twi_rxbib == 0) return 0; // if there is no stored data then returnreturn twi_rxbuffer[(twi_rxptr-1)]; //return the latest stored data}void twi_arbitrationLost(void) //for use when arbitration occurs{switch (twi_slave) //check to see if slave has been set up, if it was re-enable to inter ups and ack's{case 0: TWCR = (1 << TWEN) | (0 << TWIE) | (0 << TWINT) | (0 << TWEA); //keep in master modecase 1: TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); //set back to slave mode}twi_state = TWI_READY; //set internal status back to ready}ISR(TWI_vect){switch(TWSR){//Master status codescase TWI_START:// START has been transmittedbreak;case TWI_REP_START:// Repeated START has been transmittedbreak;case TWI_ARB_LOST:// Arbitration losttwi_arbitrationLost(); //drop out of the bus and return to ready statebreak;//MT status codescase TWI_MT_ADR_ACK:// SLA+W has been transmitted and ACK receivedbreak;case TWI_MT_ADR_NACK:// SLA+W has been transmitted and NACK receivedbreak;case TWI_MT_DATA_ACK:// Data byte has been transmitted and ACK receivedbreak;case TWI_MT_DATA_NACK:// Data byte has been transmitted and NACK receivedbreak;//MRstatus codescase TWI_MR_ADR_ACK:// SLA+R has been transmitted and ACK receivedbreak;case TWI_MR_ADR_ACK:// SLA+R has been transmitted and ACK receivedbreak;case TWI_MR_ADR_NACK:// SLA+R has been transmitted and NACK receivedbreak;case TWI_MR_DATA_ACK:// Data byte has been received and ACK transmittedbreak;case TWI_MR_DATA_NACK:// Data byte has been received and NACK transmittedbreak;//ST mode statusescase TWI_ST_ADR_ACK://own SLA+R has been received and ACK has been sent. in ST modetwi_state = TWI_ST;break;case TWI_ST_ADR_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returnedbreak;case TWI_ST_DATA_ACK:// Data byte in TWDR has been transmitted; ack has been receivedbreak;case TWI_ST_DATA_NACK:// Data byte in TWDR has been transmitted; nack has been received.break;case TWI_ST_DATA_ACK_LAST_BYTE:// Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been receivedbreak;//SR mode statusescase TWI_SR_ADR_ACK:// Own SLA+W has been received ACK has been returnedtwi_state = TWI_SR;break;case TWI_SR_ADR_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returnedbreak;case TWI_SR_GEN_ACK:// General call address has been received; ACK has been returnedbreak;case TWI_SR_GEN_ACK_M_ARB_LOST:// Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returnedbreak;case TWI_SR_ADR_DATA_ACK:// Previously addressed with own SLA+W; data has been received; ACK has been returnedtwi_rxbuffer = TWDR;//load the received data from the TWDR register into the rx buffertwi_rxptr++;//add 1 to the pointer to prevent overwritestwi_rxbib++;//add 1 to the mount of bytes in the bufferbreak;case TWI_SR_ADR_DATA_NACK:// Previously addressed with own SLA+W; data has been received; NOT ACK has been returnedtwi_rxbuffer = TWDR;//load the received data from the TWDR register into the rx buffertwi_rxptr++;//add 1 to the pointer to prevent overwritestwi_rxbib++;//add 1 to the mount of bytes in the buffertwi_arbitrationLost(); //drop out of the bus and return to ready state (same process as loosing arbitration)break;case TWI_SR_GEN_DATA_ACK:// Previously addressed with general call; data has been received; ACK has been returnedbreak;case TWI_SR_GEN_DATA_NACK:// Previously addressed with general call; data has been received; NOT ACK has been returnedbreak;case TWI_SR_STOP_RESTART:// A STOP condition or repeated START condition has been received while still addressed as Slavetwi_arbitrationLost(); //drop out of the bus and return to ready state (same process as loosing arbitration)break;//Miscellaneous statusescase TWI_BUS_ERROR:// Bus error due to an illegal START or STOP conditionTWCR = (1 << TWSTO) | (1 << TWINT); //reset bus by releasing SDA and SCL linesbreak;default: //no status code (0x00) or unknown status codetwi_arbitrationLost(); //drop out of the bus and return to ready state (same process as loosing arbitration)break;}}

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 13, 2013, 09:20:51 pm
content: just a question, is there a way to include C++ like classes in the C code. an example of this is the arduino Wire library where inside the main header file is a class function where it lists all of the higher/public functions that the user can use now i know that class is a C++ and the header files in avr studio are compiled using C is there either:a way of getting the header file to be built in C++ so that i can make use of the class functions (to be able to call functions from the main code like: CarbonWire.begin() )or is there a C code equivalent?i thinks its a nice idea and i helps the code by making it easer to see where that function is called and it hides the nitty gritty stuff within the library

author: Kremmen
author_rank: Super Contributor
timestamp: September 14, 2013, 06:05:41 am
content: Quote from: carbon dude oxide on September 13, 2013, 09:20:51 pmErr... no. They came up with C++ to do just that, you know.QuoteWhat is preventing you from turning your project into a C++ project? Or let me answer that: there is nothing preventing you from turning your project into a C++ one, only yourself. The toolchain will do it no questions asked.QuoteAnd so did Stroustrup &co when they came up with C++

author: carbon dude oxide
author_rank: Frequent Contributor
timestamp: September 14, 2013, 07:09:21 am
content: Would i have to convert the main code into c++ aswell or can i have a seperate .h and .cpp file and have it linked to the original .h file inside an extern "C" {#include "originalC.h"}Or do i have to convert it into c++ aswell?

author: Kremmen
author_rank: Super Contributor
timestamp: September 14, 2013, 07:37:21 am
content: Quote from: carbon dude oxide on September 14, 2013, 07:09:21 amIn your original post you say this:Quote from: carbon dude oxide on September 12, 2013, 10:14:28 pmso obviously, if the library is in fact a C++ class, then it is not callable from C, only C++. Yes, your main program needs to be _formally_ a C++ application. I emphasize formally, because other than being a C++ source file, it can remain essentially as is. Due to the difference in calling conventions, if you mix C and C++, you may need to guide the compiler with some extern "C" directives but other than that, no big deal.As a rule, i try to create fully self contained applications, i.e. all the code that goes into the app is part of the project source repository. Other than compiler standard libraries, that is. That way it can all be compiled as C++ and you don't need to worry about extern "C"s because there is none. The actual source code can still be vanilla C, ignoring some miniscule details, the compiler won't mind.You would then have your main() in a main.cpp file (or whatever you call it), and your i2c class in a i2c.h header and i2c.cpp source file. Include normally where needed and you are basically done. That is absolutely the way i would do it, and in fact am doing it for many peripherals. Doing this consistently will result in very "Arduino-like", easily used peripheral classes hiding all the dirty details from the main code. You just specify during instance construction (or initialization if you don't care for dynamic instances) how you wish the object to behave this time.