From: Pablo Y. T. <sh...@sa...> - 2009-01-26 22:59:37
|
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi I have a connex 400xm with a Intel PXA255 proc. I've written a realtime microkernel for this and I have/want to optimize my scheduler for a better power performance. I have a i2c current sensor (Dallas Maxim DS2745). The i2c unit works, the cabling is also correct. When I boot a GNU/Linux I'm able to read and write through the i2c bus. $ i2c 0x48 WriteByte 0x01 0 $ i2c 0x48 ReadByte 0x01 0x80 I've written a small driver for my microkernel that does not to support the whole i2c capabilities. I drive the i2c device as master the whole time and I want only to read and write bytes. I cannot use interrupts to watch over the IDBR register because of the internal structure of the context switches (which I don't want to and can't change just for this little application), so I have to do polling. I've already read the Intel PXA255 DEV document (chapter 4) a couple of times and also implemented the examples there. But these examples do not really work. I don't know exactly if I'm doing the right thing. The following pseudo code represents the steps I take: init_i2c { - clear ICR[UR] - ISR = 0 - ISAR = 1 - set ICR[IUE] - set ICR[SCLE] /* use i2c as master */ - clear ICR[UR] /* do I really need to do it? */ - clear ICR[FM] #if DEBUG - set ICR[SADIE], ICR[ALDIE], ICR[SSDIE], ICR[BEIE], ICR[IRFIE], ICR[ITEIE] - set ICMR[18] /* enabling IRQ for i2c unit */ #endif } I've written a function with which I'm able to read and write: core_i2c_multi_transfer You can define up to 5 transection that will executed with a RESTART. For example: - START - transaction 1: write 1 byte with value (let's say) 0x01 - RESTART - transaction 2: read 1 bytes (it should read 0x80) - END core_i2c_multi_transfer(tr) { while(tr is valid transaction) { - set IDBR. IDBR = (tr->address << 1) | tr->rw; (where tr->rw is 0 for a read, 1 for a write) - icr = ICR and set START and TB bits in icr; clear the STOP bit from icr ICR = icr; - simulate a timeout (ignored in DEBUG modus since IRQs are enabled): timeout = SOME_VALUE!=0 while(timeout) { timeout--; if(ISR[BED] is set) { /* BUS ERROR */ - clear ICR[TB] - if(tr->rw is read) clear ICR[ACKNAK] /* is this correct? */ - set ICR[MA]; - sleep 5 msecs - clear ICR[MA], ICR[STOP], ICR[START] - exit with failure } } /* is this correct for polling */ - for(i = 0; i < tr->num_of_bytes; ++i) { if(tr->rw == write) { - clear ICR[TB] - set IDBR with tr->data[i] (the value to be written) - icr = ICR and set TB in icr; clear START and STOP bits from icr ICR = icr; /* simulate a timeout (ignored in DEBUG modus since IRQs are enabled): */ timeout = SOME_VALUE!=0 while(ISR[ITE] is not set) { timeout--; if(timeout == 0) { /* ITE was not set, byte not written */ - clear ICR[TB], set ICR[MA], sleep 5 ms, clear ICR[MA], ICR[STOP], ICR[START] - exit with failure } } } else /* tr->rw is read */ { - icr = ICR and set ACKNAK and TB bits in icr; clear START and STOP bits from icr ICR = icr - /* simulate a timeout, same as in 'write' but ISR[IRF] is watched */ - tr->data[i] = IDBR; /* read data from the i2c bus */ - clear ICR[ACKNAK] } } tr = tr->next_tr; } - icr = ICR and set STOP and TB bits in icr; clear START bit from icr ICR = icr; - clear ICR[START] and ICR[STOP] } When I simulated $ i2c 0x48 WriteByte 0x01 0 $ i2c 0x48 ReadByte 0x01 0x80 with my function it seemed to work 1st transaction: Write 1 byte with value 0x01 2nd transaction: Read 1 byte Then I wanted to read from 0x0A (actually returns 2 bytes, but I wanted to read only the lsb) 1st transaction: Write 1 byte with value 0x0A 2nd transaction: Read 1 byte this worked, (or it seems to work since the value is most cases the same as in linux), but when I want to read 2 bytes 1st transaction: Write 1 byte with value 0x0A 2nd transaction: Read 2 bytes then the second byte cannot be read, the IRF byte is never set. If I compile my driver with #define DEBUG 1 then I see get only one Interrupt for IRF (for the first byte). How good/bad is my core_i2c_multi_transfer function? This is the first time that I have to work with a i2c controller so I'm not sure if I'm doing the things in the right way. Thanks for reading my big question. Hope anybody can help me :) Best regards Pablo - -- Pablo Yanez Trujillo http://klingsor.informatik.uni-freiburg.de/ My public key: http://klingsor.informatik.uni-freiburg.de/gpg/supertux.asc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) iEYEARECAAYFAkl+KW0ACgkQDzf8xo+0xRUdDQCg1Rc06GfxeAfYHOQDprhSkj3V xVIAoJ5mZ4RfPrteOR4qBIvdNZAcfo+i =MGGQ -----END PGP SIGNATURE----- |