Open davec2 opened 11 years ago
I usually see "IOError: [Errno 5] Input/output error" when I'm trying to send to a non-existent address.
Have you successfully sent single bytes?
Hello Nat,
Sorry for the delay in responding!
I have indeed been able to successfully send single bytes.
Dave
Date: Sun, 3 Feb 2013 15:02:11 -0800 From: notifications@github.com To: quick2wire-python-api@noreply.github.com CC: broadsword999@hotmail.com Subject: Re: [quick2wire-python-api] I2C writing and writing_bytes cannot seem to write more than 2 bytes of data at a time (#27)
I usually see "IOError: [Errno 5] Input/output error" when I'm trying to send to a non-existent address.
Have you successfully sent single bytes?
—
Reply to this email directly or view it on GitHub.
I've just done a test writing and reading multiple bytes to a 24LC512 eeprom, and everything works as expected.
Dave, what is the device you are writing to?
Sorry for the delay in responding!
That's curious - I am writing to an Atmel Atmega168, which has been programmed to send and receive multiple bytes via I2C. I've tested the Atmega168 and found it to work with other devices. But when I tried to write to it with the quick2wire api, I couldn't get more than 2 bytes to go across at a time. I confirmed this with an I2C protocl analyzer (a gabotronics xprotolab). I wonder what is different? I'm tempted to send one of these to you to see if you can get it to work.
The code I have running on the Atmega168 is on my other computer -I'll get it out to you as an attachment if you want.
Cheers, Dave
Date: Sun, 17 Feb 2013 07:25:06 -0800 From: notifications@github.com To: quick2wire-python-api@noreply.github.com CC: broadsword999@hotmail.com Subject: Re: [quick2wire-python-api] I2C writing and writing_bytes cannot seem to write more than 2 bytes of data at a time (#27)
I've just done a test writing and reading multiple bytes to a 24LC512 eeprom, and everything works as expected.
Dave, what is the device you are writing to?
—
Reply to this email directly or view it on GitHub.
Thanks for the extra background. A copy of the 168 code would be useful.
As it happens, some of the code I need to work on today involves sending I2C data from a Pi to an arduino clone. So far I've been sending single bytes but today I'll try more than one. I'll capture bus activity with the Open Workbench Logic Sniffer and report results.
I'm sorry you're experiencing problems, but this kind of user feedback is really valuable. Either our code is doing something wrong, (in which case we need to find and fix it), or you are (in which case our documentation is defective, and we need to fix that).
I've copied this to our user group, just in case someone else has similar problems or has an idea of what's going wrong.
On 26 February 2013 00:53, davec2 notifications@github.com wrote:
Sorry for the delay in responding!
That's curious - I am writing to an Atmel Atmega168, which has been programmed to send and receive multiple bytes via I2C. I've tested the Atmega168 and found it to work with other devices. But when I tried to write to it with the quick2wire api, I couldn't get more than 2 bytes to go across at a time. I confirmed this with an I2C protocl analyzer (a gabotronics xprotolab). I wonder what is different? I'm tempted to send one of these to you to see if you can get it to work.
The code I have running on the Atmega168 is on my other computer -I'll get it out to you as an attachment if you want.
Cheers, Dave
Date: Sun, 17 Feb 2013 07:25:06 -0800 From: notifications@github.com To: quick2wire-python-api@noreply.github.com CC: broadsword999@hotmail.com Subject: Re: [quick2wire-python-api] I2C writing and writing_bytes cannot seem to write more than 2 bytes of data at a time (#27)
I've just done a test writing and reading multiple bytes to a 24LC512 eeprom, and everything works as expected.
Dave, what is the device you are writing to?
—
Reply to this email directly or view it on GitHub.
— Reply to this email directly or view it on GitHubhttps://github.com/quick2wire/quick2wire-python-api/issues/27#issuecomment-14086245 .
http://quick2wire.com safe, simple connection to your Raspberry Pi
Sorry for taking this long to get back to you - it has been a rather strange few days.
So anyway, I have attached the code which I programmed onto the Atmel AVR ATMEGA168 processor. The code reflects the send-one-byte-at-a-time nature that I discovered when running the python module on the RPi. However, I direct your attention to the function handleI2C() - in it is a case statement which first tests for TW_STATUS equaling 0x60; the condition on r_index >= BUFLEN_RECV should allow the Atmega to return a NACK; this should then allow the I2C master to send more bytes. For whatever reason, I could not get this to work on the RPi with the quick2wire module, most likely due to my feeble programming skills more than anything else. I would be most grateful if you could see if you can get it to work.
I've written this code so that one byte per I2C write can be received. In order to return it to it original state, where it will try to receive 5 bytes at a go, do the following: uncomment line 178 comment out lines 288,289, and291 I compiled this on AVR Studio 4 running on a Windows 7 machine. The dependencies are the usual set of gcc libraries from AVRStudio. I do remember starting out with some I2C slave code obtained from the internet (perhaps AVR Freaks' forum??), but I cannot now recall from where I got it.
I hope this helps. I am quite interested in hearing how well it works (or doesn't)!
Dave Date: Mon, 25 Feb 2013 23:10:14 -0800 From: notifications@github.com To: quick2wire-python-api@noreply.github.com CC: broadsword999@hotmail.com Subject: Re: [quick2wire-python-api] I2C writing and writing_bytes cannot seem to write more than 2 bytes of data at a time (#27)
Thanks for the extra background. A copy of the 168 code would be useful.
As it happens, some of the code I need to work on today involves sending
I2C data from a Pi to an arduino clone. So far I've been sending single
bytes but today I'll try more than one. I'll capture bus activity with the
Open Workbench Logic Sniffer and report results.
I'm sorry you're experiencing problems, but this kind of user feedback is
really valuable. Either our code is doing something wrong, (in which case
we need to find and fix it), or you are (in which case our documentation is
defective, and we need to fix that).
I've copied this to our user group, just in case someone else has
similar problems or has an idea of what's going wrong.
On 26 February 2013 00:53, davec2 notifications@github.com wrote:
Sorry for the delay in responding!
That's curious - I am writing to an Atmel Atmega168, which has been
programmed to send and receive multiple bytes via I2C. I've tested the
Atmega168 and found it to work with other devices. But when I tried to
write to it with the quick2wire api, I couldn't get more than 2 bytes to go
across at a time. I confirmed this with an I2C protocl analyzer (a
gabotronics xprotolab). I wonder what is different? I'm tempted to send one
of these to you to see if you can get it to work.
The code I have running on the Atmega168 is on my other computer -I'll get
it out to you as an attachment if you want.
Cheers,
Dave
Date: Sun, 17 Feb 2013 07:25:06 -0800
From: notifications@github.com
To: quick2wire-python-api@noreply.github.com
CC: broadsword999@hotmail.com
Subject: Re: [quick2wire-python-api] I2C writing and writing_bytes cannot
seem to write more than 2 bytes of data at a time (#27)
I've just done a test writing and reading multiple bytes to a 24LC512
eeprom, and everything works as expected.
Dave, what is the device you are writing to?
—
Reply to this email directly or view it on GitHub.
—
Reply to this email directly or view it on GitHubhttps://github.com/quick2wire/quick2wire-python-api/issues/27#issuecomment-14086245
.
http://quick2wire.com safe, simple connection to your Raspberry Pi
— Reply to this email directly or view it on GitHub.
//global variables
uint8_t r_index =0; uint8_t recv[BUFLEN_RECV]; //buffer to store received bytes
uint8_t t_index=0; //test bytes to transmit uint8_t tran[BUFLEN_TRAN] = {0x12, 0x34, 0x56};
//variable to indicate if something went horribly wrong uint8_t reset=0;
int timer0_overflow_count; volatile unsigned char timer0_overflow_flag;
//globals for our input packet // recv[0] is new_cmd; 1 for new_cmd; 0 for when executed // recv[1] is motor; 0,1,2,3,4,5 or 6 for respective motor // recv[2] is speed; 255 for slowest, 0 for fastest // recv[3] and recv[4] = dur_1 and dir_0 // // dur_1 and dur_0 make a two byte value for duration in milliseconds // that is, duration of how long the motor is on at the desired speed. // the two bytes are decimal coded - that is, only acceptable values are numerics // from 00 to 99 for each byte. This means the largest duration is 9999 msec, or just under // 10 seconds. This should be ok?? // Isn't there a way to easily convert hex to decimal? //
char new_cmd = 0; char motor = 0; char speed = 255; char dur_1,dur_0;
//setup the I2C hardware to ACK the next transmission //and indicate that we've handled the last one.
//setup the I2C hardware to NACK the next transmission
//reset the I2C hardware (used when the bus is in a illegal state)
// ** // \ define ISRs // // ****
/*SIGNAL(SIG_OVERFLOW0) { timer0_overflow_count++; timer0_overflow_flag = 1; // flag the overflow }
*/
ISR(TIMER0_OVF_vect) { timer0_overflow_count++; timer0_overflow_flag = 1; // flag the overflow }
ISR(TIMER1_COMPA_vect) { //based on the global variable for motor, we toggle a specific bit of PORTB to // activate the appropriate motor. The TOG function linked to the ISR TIMER1_COMPA_vect // will make the appropriate PORTB bit act like a PWM output. switch(motor) { case(0): SET(PORTB,6);break; case(1): SET(PORTB,5);break; case(2): SET(PORTB,4);break; case(3): SET(PORTB,3);break; case(4): SET(PORTB,2); break; //case(5): // TOG(PORTB,0); break; default: // do nothing break; }
}
ISR(TIMER1_OVF_vect) //based on the global variable for motor, we toggle a specific bit of PORTB to // activate the appropriate motor. The TOG function linked to the ISR TIMER1_OVF_vect // will make the appropriate PORTB bit act like a PWM output. { switch(motor) { case(0): CLR(PORTB,6);break; case(1): CLR(PORTB,5);break; case(2): CLR(PORTB,4);break; case(3): CLR(PORTB,3);break; case(4): CLR(PORTB,2); break; //case(5): // TOG(PORTB,0); break; default: // do nothing break; }
}
// // functions // unsigned long millis() { unsigned long count; do { timer0_overflow_flag = 0; // clear the overflow flag count = timer0_overflow_count; // read timer0_overflow_counter } while (timer0_overflow_flag); // if an overflow occurred during the read, try again
return count * 64UL * 2UL / (F_CPU / 128000UL);
}
void delayms( uint16_t millis ) { while ( millis ) { _delay_ms( 1 ); millis--; } }
void handleI2C(){
//check if we need to do any software actions
if(CHK(TWCR,TWINT)){
switch(TW_STATUS){
//--------------Slave receiver------------------------------------
//SLA_W received and acked, prepare for data receiving
case 0x60:
TWACK;
//r_index =0;
break;
case 0x80: //a byte was received, store it and
//setup the buffer to recieve another
recv[r_index] = TWDR;
r_index++;
//don't ack next data if buffer is full
if(r_index >= BUFLEN_RECV){
TWNACK;
}else {
TWACK;
}
break;
case 0x68://adressed as slave while in master mode.
//should never happen, better reset;
reset=1;
case 0xA0: //Stop or rep start, reset state machine
TWACK;
break;
//-------------- error recovery ----------------------------------
case 0x88: //data received but not acked
//should not happen if the master is behaving as expected
//switch to not adressed mode
TWACK;
break;
//---------------Slave Transmitter--------------------------------
case 0xA8: //SLA R received, prep for transmission
//and load first data
t_index=1;
TWDR = tran[0];
TWACK;
break;
case 0xB8: //data transmitted and acked by master, load next
TWDR = tran[t_index];
t_index++;
//designate last byte if we're at the end of the buffer
if(t_index >= BUFLEN_TRAN) TWNACK;
else TWACK;
break;
case 0xC8: //last byte send and acked by master
//last bytes should not be acked, ignore till start/stop
//reset=1;
case 0xC0: //last byte send and nacked by master
//(as should be)
TWACK;
break;
//--------------------- bus error---------------------------------
//illegal start or stop received, reset the I2C hardware
case 0x00:
TWRESET;
break;
}
}
}
int true_convert(char dur_1, char dur_0) { // convert dur_1 | dur_0 to a decimal integer int actual;
actual = dur_1*100 + dur_0; return actual;
// maybe could do some limit checking here or accept other conversions?
}
//---------------MAIN--------------------------------------------- int main(){ int dly = 0; //load slave address TWAR = (0x01<<1); //we're using address 0x01 //enable I2C hardware TWCR = (1<<TWEN)|(1<<TWEA); // initially set all I/O related to OCRnx to input // for Atmega168, we have the following // OC2B = PD3 // OC2A = PB3 // OC0B = PD5 // OC0A = PD6 // OC1A = PB1 // OC1B = PB2
//DDRD = 0b10010111; DDRB = 0xff;
// setup the PWM counters
TCCR1A = 0b00000001; // turn off the ocr1a/1b output as normal startup condition. TCCR1A = 0b10100001; //
TCCR1B = 0b00001011; //
TIMSK1 = 0x00; // enable interrupt on ocie1a - match on ocr1a - this will be used to toggle another port
// timer 0 is used for the delayms function
// TCCR0A = 0b10100011;
// TCCR0B = 0b00000011; //fast PWM, clk / 64
// need to add TCCR2A and B to make 6 PWM output signals
//TCCR2A = 0b10100011;
//TCCR2B = 0b00000100;
// some comments: (1) timer0 is being used for both a pwm and for the delayms function. Can have only
// one mode and one use at a time. if as delay, then not also as PWM - we lose two pwm outputs here.
//
// changing the ddr of a port might do nothing to the ocx outputs: instead, we will likely need to
// turn on and off the counter itself using TTC1n registers.
//
// isn't there an sbi() assembly command that allows one to toggle any port bit based on a counter??
// maybe we can gain back the two outputs by toggling other port bits (on command of counter 2 and
// counter 1, based on the command sent over i2c?
sei();
while(1){ while(r_index <5) { handleI2C(); } new_cmd = recv[0]; motor = recv[1]; speed = recv[2]; dur_1 = recv[3]; dur_0 = recv[4]; //OCR0A = 0; //OCR0B = 0; OCR1A = 0; OCR1B = 0; //OCR2A = 0; //OCR2B = 0;
if (new_cmd == 1) { //DDRB = 0xff; new_cmd = 0; // reset to 0 so that only a newly sent command will get us back here // reset what we received from i2c: recv[0]=0;recv[1]=0;recv[2]=0;recv[3]=0;recv[4]=0; dly = true_convert(dur_1,dur_0); TCCR1A = 0b10000001; // turn on compare match output of counter TCNT1 = 0xff; // to ensure we always get the proper polarity of our PWM OCR1A = speed; // set the PWM speed TIMSK1 = 0x03; delayms(dly); // allow to run for specified amount of time TCCR1A=0x01; // disable the PWM output TIMSK1 = 0x00; PORTB = 0x00; // make certain all the motors are OFF r_index = 0; // get ready for next i2c transaction // the problem with this is that until we complete the one motor command, // we will be unable to see a new command. // so the host should likely write a motor command (5 bytes), then // read a status [polling]. When that status is done, then can write another // command.
//
// all because neither arduPi nor quick2wire-python-api can apparently reliably
// send more than one byte at a given i2c write (!!!)
//DDRB = 0x00;
//
// ISR(TIMER1_COMPA_vect) selects the appropriate bit to toggle based on motor value.
} } } //-----------END MAIN---------------------------------------------
I think this is an issue. It caught me by surprise, but sometimes that doesn't take much. I hope this is the correct place for this topic.
I'm running Rasparian wheezy with kernel 3.2.27 on a Rev 2 RPi, and am attempting to write more than 2 bytes to an I2C slave device. I did the following in python3: import quick2wire.i2c as i2c address = 0x01 with i2c.I2CMaster() as bus: bus.transaction(i2c.writing_bytes(address, 0x01,0x02))
I get the following error:
File "/home/pi/quick2wire-python-api-master/quick2wire/i2c.py", line 74, in transaction ioctl(self.fd, I2C_RDWR, ioctl_arg)
IOError: [Errno 5] Input/output error
I have an I2C sniffer on the SDA and SCL pins - I see the two bytes on the line, but I still get this error.
Further, if I try to send more than 2 bytes, I only ever see just the first two bytes on the I2C bus, and I get the same error as above.
I was under the impression that I could send any length of byte values using the i2c.py methods?