Martin Guy |
On 15 June 2011 18:36, Laurent Dufrechou <[hidden email]> wrote:
>> On LM3S it should be: >> platform_i2c_start_and_send_address(0, address) >> platform_i2c_send_byte( 0, false, &data, 20); >> platform_i2c_recv_byte( 0, true, &data_rcv, 50); //true means stop. >> >> You mean that i2c send can't be called 2 consecutive times on avr32? >>1) Redefine the eLua I2C APIs to express full I2C transfers as an >>arbitrary sequence of sends and receives. > > I follow you, it is too complex also from my point of view >>2) Leave the interface as it is and implement I2C on AVR32 as a >>bit-banging interface, completely forgetting their TWI hardware. > > Not efficient as you said. In terms of execution speed it is about the same, since we must wait for the ACKs on sending, and must wait until the data arrives on receiving. I guess it uses more electrical power to do this with the CPU than with the hardware. My own problem with this is how disgusting it is to have to do it this way! > I prefer this approach but your restrain too much to your CPU way of doing. Yes. I see that you can implement more of I2C with your interface, but it doesn't express the possibility of different slave addresses between packets, which is needed for the synchronized data acquisition case. What do you think of just two functions: platform_i2c_master_send( id, address, &data, 20, false ); platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means stop. (hey, I moved the STOP flag to the end :) On AVR32, I need to know all the sending data and the receiving data at the same time, but I can do the one repeated-start case that it can perform by recognising the first part (send with 1-3 bytes and no stop), make a copy of the address and the 1-3 bytes, then use this data if the next call is a receive from the same address with stop. If you can't change the slave address between packets on LMS3/STR9, just check that it is the same? M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Laurent Dufrechou |
>What do you think of just two functions:
> >platform_i2c_master_send( id, address, &data, 20, false ); >platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means stop. >(hey, I moved the STOP flag to the end :) I see, with a static flag I can see that there is an ongoing transfer and thus I can ignore address parameter. It Seems OK for me. I will try it tomorrow and I'll keep you updated. Laurent _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
On 15 June 2011 21:58, Laurent Dufrechou <[hidden email]> wrote:
>>What do you think of just two functions: >> >>platform_i2c_master_send( id, address, &data, 20, false ); >>platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means > stop. > > I see, with a static flag I can see that there is an ongoing transfer and > thus I can ignore address parameter. I'm not sure why you would ignore it... if I understand your datasheet (first download link at http://www.luminarymicro.com/products/LM3S8962.html#Datasheet pages 510/511) you have to program the slave address again after a repeated start. Does their SDK API hides this? Anyway... M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Hi,
Thanks for this thread. I'll jump in as soon as I can, at this point I simply can't find enough time to get a better view of the I2C implementations on our supported targets and come up with a generic interface on top of them. It's a bit ironic that we're having such problems with an interface as simple as I2C, but life can be ironic at times :)
Martin, please see below. On Thu, Jun 16, 2011 at 2:27 AM, Martin Guy <[hidden email]> wrote:
I love the simplicity of this and if it proves to be enough I'll not hesitate in implementing it. It hides some lower level I2C operations but as we learnt they aren't always possible to implement on our platforms. Still thinking what to do with the lower level ops (send start, send stop and so on). As I see it at the moment, since they're probably rarely needed in practice a good place for them would be in a platform specific module (stm32.i2c or str9.i2c for example). Or maybe still in the main I2C interface (since they are after all fundamental I2C operations), letting the user know if the platform is unable to implement them. I can see this turning into a philosophical discussion fast, so I'll leave it for now ;)
One question: how does your interface above handle situations like reading from an I2C EEPROM? The sequence of operations is this: 1. Send start and I2C address with WRITE bit on 2. Get acknowledge from slave (the EEPROM)
3. Send the memory address to read from to slave (2 or 3 bytes). Do NOT send stop. 4. Send start again (repeated start) and I2C address with READ bit on 5. Read data, acknowledge all bytes but the last one
6. Send STOP (for a full reference of the protocol check for example the datasheet of 24LC256 here : http://wulfden.org/downloads/datasheets/24LC256.pdf)
I don't know how to implement steps 3-4 above with your interface. Best, Bogdan _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Laurent Dufrechou |
Hi, platform_i2c_master_send( 0, address, &data, 3, do_stop=false ); Will work since first function: - will send an address + data in write mode and do not send stop. (last parameter is =false). And next function: - you resend address + get 50 data with a stop at end.(last parameter is =true). For the 2nd function since, you have not stop the transfer with 1st function, it will do logically a repeated start. I think this is the idea Laurent De : [hidden email] [mailto:[hidden email]] De la part de Bogdan Marinescu Hi, Thanks for this thread. I'll jump in as soon as I can, at this point I simply can't find enough time to get a better view of the I2C implementations on our supported targets and come up with a generic interface on top of them. It's a bit ironic that we're having such problems with an interface as simple as I2C, but life can be ironic at times :) Martin, please see below. On Thu, Jun 16, 2011 at 2:27 AM, Martin Guy <[hidden email]> wrote: On 15 June 2011 21:58, Laurent Dufrechou <[hidden email]> wrote: I love the simplicity of this and if it proves to be enough I'll not hesitate in implementing it. It hides some lower level I2C operations but as we learnt they aren't always possible to implement on our platforms. Still thinking what to do with the lower level ops (send start, send stop and so on). As I see it at the moment, since they're probably rarely needed in practice a good place for them would be in a platform specific module (stm32.i2c or str9.i2c for example). Or maybe still in the main I2C interface (since they are after all fundamental I2C operations), letting the user know if the platform is unable to implement them. I can see this turning into a philosophical discussion fast, so I'll leave it for now ;) One question: how does your interface above handle situations like reading from an I2C EEPROM? The sequence of operations is this: 1. Send start and I2C address with WRITE bit on 2. Get acknowledge from slave (the EEPROM) 3. Send the memory address to read from to slave (2 or 3 bytes). Do NOT send stop. 4. Send start again (repeated start) and I2C address with READ bit on 5. Read data, acknowledge all bytes but the last one 6. Send STOP (for a full reference of the protocol check for example the datasheet of 24LC256 here : http://wulfden.org/downloads/datasheets/24LC256.pdf) I don't know how to implement steps 3-4 above with your interface. Best, Bogdan _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Hi,
On Thu, Jun 16, 2011 at 12:46 PM, Laurent Dufrechou <[hidden email]> wrote:
Thanks, it makes sense now :) Best, Bogdan
_______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Laurent Dufrechou |
In reply to this post by Martin Guy
You're right but :) I was thinking of the (dumb) case where a guy want to
do: platform_i2c_master_send( id, address, &data_a, 20, false ); platform_i2c_master_send( id, address, &data_b, 20, false ); platform_i2c_master_send( id, address, &sync, 1, true ); Where someone, wants to send multiple bursts without resending the address (on line 2 and 3). The advantage of separating address sending in its own function call is that such crazy cases are de-facto taken into account. But still I see how to handle such case with some kind of simple state machine. Regards, Laurent -----Message d'origine----- De : Martin Guy [mailto:[hidden email]] Envoyé : jeudi 16 juin 2011 01:28 À : Laurent Dufrechou Cc : eLua Users and Development List (www.eluaproject.net) Objet : Re: [eLua-dev] Redefining the I2C Lua interface (was: I2C for LM3S devices) On 15 June 2011 21:58, Laurent Dufrechou <[hidden email]> wrote: >>What do you think of just two functions: >> >>platform_i2c_master_send( id, address, &data, 20, false ); >>platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means > stop. > > I see, with a static flag I can see that there is an ongoing transfer and > thus I can ignore address parameter. I'm not sure why you would ignore it... if I understand your datasheet (first download link at http://www.luminarymicro.com/products/LM3S8962.html#Datasheet pages 510/511) you have to program the slave address again after a repeated start. Does their SDK API hides this? Anyway... M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
In reply to this post by BogdanM
On 16 June 2011 08:22, Bogdan Marinescu <[hidden email]> wrote:
> I can see this > turning into a philosophical discussion fast, so I'll leave it for now ;) I have no problems with that, because it is a question of the guiding principles for good API design. Question: How do you go about designing a good API for I2C that will be able to drive all devices and usage situations, including ones we have never heard of, and that can be implemented on I2C master devices, including those we have never tried to implement it on? Answer: Make the API reflect the I2C specification, which is where these two classes of devices meet. To be more precise, defining a good API is choosing a language that: 1) is generic enough to let you ask for any operation that is valid. 2) is restrictive enough that you cannot express invalid operations. 3) is not so complex as to be awful to use It's the conflict between these requirements that helps us refine the best API for the circumstances. If we make the API talk I2C, then for the device driver interfaces that we have: - for the devices that work in terms of START bits, you implement the valid I2C operations that the API asks for using legal sequences of those low-level primitives - for the crippled ones like AVR32, you implement the things they are able to do and fail the valid operations that they cannot perform That's enough philosophy :) I'll answer the specific questions in the next post. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
In reply to this post by BogdanM
On 16 June 2011 08:22, Bogdan Marinescu <[hidden email]> wrote:
> I simply can't find enough time to get a better view of the I2C > implementations on our supported targets and come up with a generic > interface on top of them. If the generic interface can express I2C well, it will be appropriate for all I2C hardware. Specific pieces of hardware are cases that test whether the API is appropriate, but are not what define it. For example, if you look at the broken AVR32 hardware, you might conclude (like I did) that the only valid case of repeated start is when you send 1, 2 or 3 bytes and receive N. Fortunately, Laurent stopped me from doing that! (Thanks, L!) >> platform_i2c_master_send( id, address, &data, 20, false ); >> platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means stop. > > I love the simplicity of this and if it proves to be enough I'll not > hesitate in implementing it. It hides some lower level I2C operations but as > we learnt they aren't always possible to implement on our platforms. > Still thinking what to do with the lower level ops (send start, send stop and so on) They can be used to implement the valid I2C operations. For example: platform_i2c_master_send( id, address, data, nbytes, true ); is platform_i2c_send_start( id ); platform_i2c_send_address( id, address, PLATFORM_I2C_DIRECTION_TRANSMITTER ); for (i=0; i<nbytes; i++) platform_i2c_send_byte( id, data[i] ); platform_i2c_send_stop( id ); In fact, if we add checking for success and "if (stop) platform_i2c_send_stop( id )", that is the implementation of the new interface on the existing platforms. We don't even need to remove the existing platform functions, just make them static when the old interface is removed. > As I see it at the moment, since they're probably rarely needed in > practice a good place for them would be in a platform specific module > (stm32.i2c or str9.i2c for example) If we get the platform interface right, that can express all valid I2C operations and no invalid ones, they won't be necessary. A good API would not allow people to say START START STOP ADDRESS STOP The questions are: 1) is it sufficient to express everything that is valid I2C? 2) does it allow people to express things that are not valid I2C? As far as i can see, it allows any valid I2C sequence to be sent, including arbitrary sequences of writes and reads with repeated starts, maybe to different slave devices, which is valid I2C and is used to initialize a series of data acquisition devices and have them all start capturing data in sync when the final STOP is sent. The only invalid I2C that I can see it allowing is if they forget to set STOP on the very last message before the program exits. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Laurent Dufrechou |
In reply to this post by Martin Guy
Just to come back on why I don't like having address with data in same
function is: How do you do this whit your model?: void XXXX_writeRegister(u8 reg, u8 data) { I2C_startAndSendAddress(I2C_0, XXXXXX, I2C_WRITE); I2C_sendBytes(I2C_0, ®, 1, false); //no stop I2C_sendBytes(I2C_0, &data, 1, true); //repeat start and stop } In your function definition, each time I will have to concatenate all my data in buffer. Ex: void XXXX_writeRegister(u8 reg, u8 data) { Buff[0]=reg; Buff[1]=data; I2C_startAndSendAddress_and_sendBytes(I2C_0, startAndSendAddress &buff, 2, true); //do stop } This why I separated address from data. I find it more near from hardware. Now if avr32 does not support this model, let's go for your option. Both approaches are ok :) I will be interested to see NXP components works... :) Any thought? -----Message d'origine----- De : Martin Guy [mailto:[hidden email]] Envoyé : jeudi 16 juin 2011 01:28 À : Laurent Dufrechou Cc : eLua Users and Development List (www.eluaproject.net) Objet : Re: [eLua-dev] Redefining the I2C Lua interface (was: I2C for LM3S devices) On 15 June 2011 21:58, Laurent Dufrechou <[hidden email]> wrote: >>What do you think of just two functions: >> >>platform_i2c_master_send( id, address, &data, 20, false ); >>platform_i2c_master_recv( id, address, &data_rcv, 50, true ); //true means > stop. > > I see, with a static flag I can see that there is an ongoing transfer and > thus I can ignore address parameter. I'm not sure why you would ignore it... if I understand your datasheet (first download link at http://www.luminarymicro.com/products/LM3S8962.html#Datasheet pages 510/511) you have to program the slave address again after a repeated start. Does their SDK API hides this? Anyway... M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
How about (high level:
write_to_address( id, address, data, len send_stop) write( id, data, len, send_stop ) --> (no address involved) read_from_address( id, address, data, len, send_stop )
read( id, data, len, send_stop ) --> (no address involved) The sequence for buffer operations would be: 1. write_to_address 2. write 3. repeat 2 with all data to write
(the same goes for read). At Lua level we could further abstract this by calling write_to_address/write or read_from_address/read automatically from the I2C module. As an advantage, the state machine required by this would be platform independent since we'd implement it directly in the I2C module code.
Would this fix the problem? Best, Bogdan
On Thu, Jun 16, 2011 at 4:52 PM, Laurent Dufrechou <[hidden email]> wrote: Just to come back on why I don't like having address with data in same _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
In reply to this post by Laurent Dufrechou
On 16 June 2011 15:52, Laurent Dufrechou <[hidden email]> wrote:
> Just to come back on why I don't like having address with data in same > function is: > How do you do this whit your model?: > > void XXXX_writeRegister(u8 reg, u8 data) > { > I2C_startAndSendAddress(I2C_0, XXXXXX, I2C_WRITE); > I2C_sendBytes(I2C_0, ®, 1, false); //no stop > I2C_sendBytes(I2C_0, &data, 1, true); //repeat start and stop > } You don't. Sending data bytes after a start without an address is not valid I2C protocol; every START condition must always be followed by a slave address. But I think maybe the "//repeat start" comment is a mistake in the above; it looks like sendBytes knows nothing about repeated starts or slave addresses. > In your function definition, each time I will have to concatenate all my > data in buffer. > Ex: > void XXXX_writeRegister(u8 reg, u8 data) > { > Buff[0]=reg; > Buff[1]=data; > I2C_startAndSendAddress_and_sendBytes(I2C_0, startAndSendAddress > &buff, 2, true); //do stop > } That's right. I2C does not define anything about what the data bytes after the slave address mean: if the data selects a device's internal register and then the data for that register, that is just data as far as I2C is concerned. So yes, for devices that take "register_number; register_value" as data you have to put the register number and value in a single buffer. If you want to have a primitive to read/write registers in a specific I2C device like an EEPROM, the right place to do that is in a Lua module built on top of the eLua i2c interface. > I find it more near from hardware. Now if avr32 does not support this model, > let's go for your option. No, you can't do half a write and then the other half with AVR32, because you can't stop the sending hardware in the middle of the data of a packet and then carry on and stop later. You have to have all the data already available at the start of the transfer. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
In reply to this post by BogdanM
On 16 June 2011 16:04, Bogdan Marinescu <[hidden email]> wrote:
> How about (high level: > write_to_address( id, address, data, len send_stop) > write( id, data, len, send_stop ) --> (no address involved) > read_from_address( id, address, data, len, send_stop ) > read( id, data, len, send_stop ) --> (no address involved) > The sequence for buffer operations would be: > 1. write_to_address > 2. write > 3. repeat 2 with all data to write The register_number+value or eeprom_memory_address+data_to_write are not part of I2C. That's the format that DS1337 Real time clock and 24LC32A EEPROM, for example, impose on top of the I2C data stream to get separate pieces of information that they need, but that's nothing to do with I2C itself. The register+value formats and the address+data formats are a higher level than I2C: devices imposes another level of structure on top of the I2C protocol, by saying that different bytes of the data have specific meanings. The matching place to do that in the API is a higher level EEPROM API that which concatenates the register number and its value (or EEPROM memory address and data) into a single string and calls the i2c API with that. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
On Thu, Jun 16, 2011 at 5:44 PM, Martin Guy <[hidden email]> wrote:
I completely agree with you, but my point was that at the lowest I2C level (that we can afford :) ) we need to be able to do write without an address too. Having to send the device address each time we write something is a limitation in the interface.
It gets even more interesting with reads, where sometimes the protocol requires that the master acknowledges every byte read from the slave EXCEPT the last one. If we do chunked reads (read_from_address followed by read) we can't know in advance when the last one will be sent. I'm guessing that the read functions need another parameter (ack_last_byte).
While writing this, it occured to me that this simple interface might still not be good enough for EEPROMs (I'm coming back to this use case all the time because it's the one I know best). After an EEPROM receives the data to write it needs some time to write it, during this time it will not be accesible and it will not ACK its device address. This is how the master knows when the EEPROM finished the write operation: it polls it by sending start+its address on the I2C bus and checks for an ACK. This is called acknowledge polling. From the 24LC256 manual:
Since the device will not acknowledge during a write cycle, this can be used to determine when the cycle is complete (This feature can be used to maximize bus throughput). Once the Stop condition for a Write
command has been issued from the master, the device initiates the internally timed write cycle. ACK polling can be initiated immediately. This involves the master sending a Start condition, followed by the control byte
for a Write command (R/W = 0). If the device is still busy with the write cycle, then no ACK will be returned. If no ACK is returned, the Start bit and control byte must be resent. If the cycle is complete, then the device will
return the ACK and the master can then proceed with the next Read or Write command. Not sure how to implement this with our interface. Maybe with a write_to_address with an empty (NULL) buffer, assuming that reads/writes return an error if the slave device didn't ACK (which is a good idea anyway). A bit ugly, but it should work.
Best, Bogdan
_______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
On 16 June 2011 17:00, Bogdan Marinescu <[hidden email]> wrote:
> at the lowest I2C level > (that we can afford :) ) we need to be able to do write without an address > too. The current implementation of i2c.write( id, data1, [data2], [data3], ... ) relies on this, yes, but that's going to have to be rewritten too. If you want to take a variable number of parameters in the new i2c.send(), you'll have to concatenate their values into a Lua buffer before calling the C platform interface with the whole data packet. In fact, that might be a good feature to keep, making it easier for users to construct structured I2C data packets. Keep that thought in mind a moment... Anyway, AVR32 cannot write data without an address; the hardware can only handles complete I2C packets, so that's that. If you go back to function calls that write half an I2C packet, the AVR32 is going to have to collect them up until it gets a stop and then send them all. That means being able to allocate arbitrary amounts of RAM in the C device driver, which I don't think is desirable. Furthermore, if you make the C platform interface deal only in whole I2C packets, you can be sure to be able to implement I2C on other future hardware platforms that also only deal in complete I2C packets. AVR32 is just the first example we have found that needs this. > If we do chunked reads (read_from_address followed by read) we > can't know in advance when the last one will be sent. I'm guessing that the > read functions need another parameter (ack_last_byte). Yuck! Why would you want to read half a response? > After an EEPROM receives the data to > write it needs some time to write it, during this time it will not be > accesible and it will not ACK its device address. Hmm. Well, once you define the eeprom-reading and eeprom-writing functions in Lua on top of the I2C module, you can move the check there. Assuming you have already probed for the presence of the EEPROM, one idea is something like: I'm also assuming the new i2c.send takes the same mutiple data parameters as i2c.write -- read data from eeprom with 16-bit address sent high byte first. function i2c.eeprom.read( id, slave, mem_addr, nbytes ) -- i2c.send: assuming nil means failure and some integer means the number of bytes written repeat until i2c.send( id, slave, false, msb( mem_addr ), lsb( mem_addr ) ) -- i2c.recv: assuming nil means failure, otherwise a string of the data received return i2c.recv( id, slave, true, nbytes ) end function i2c.eeprom.write( id, slave, mem_addr, data ) repeat result = i2c.send( id, slave, true, msb( mem_addr ), lsb( mem_addr ), data ) until result -- How many of the data bytes were written? if result < 2 return nil else return result - 2 fi end Again, the fact that these are in Lua reflects the fact that the EEPROM data format is not part of I2C. It's just one device that happens to fill the I2C data with a 16-bit address in high-byte then low-byte order, followed by the data to write to EEPROM. My own problem with i2c.probe(id, address) is that AVR32 cannot send empty data packets. Do you happen to know what an I2C EEPROM does if you send it a single 0 byte (just the MSB of the memory address). Ignores it, I hope; the spec doesn't say. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
On Thu, Jun 16, 2011 at 6:54 PM, Martin Guy <[hidden email]> wrote:
I know you're probably sick and tired of my EEPROM examples :) but I'm going to get back to that again. In one of my applications I actually read the whole content of a serial EEPROM (32KB (not Kb)) into a file in the filesystem. Reading the whole data and writing it in one step is simply not good enough because I'd need too much memory for the operation, so instead I'm reading it in chunks of 256 bytes. For this kind of application, an "I2C data packet" is an undefined concept, as the packet can be as large as the memory itself, as small as 1 byte of data or an arbitrary size (256 bytes of data). I specify the memory address (0) only at the beginning, then I keep on reading data until I have enough, at which point I send a "stop". Yes, I can also do this by issuing repeated "read" commands with increasing addresses, but that adds an overhead. And I'm not worried about the actual impact of the overhead (which is very small), I just feel that the I2C interface introduces limitations that shouldn't be there ...
Keep that thought in mind a moment... Hopefully my example above answers your questions.
Absolutely. I'm not using EEPROM as an example because I want to model our I2C platform interface after it, it's just an use case I'm quite familiar with in practice and I can use it to detect limitations in our interface. So far it's doing a pretty good job :)
My own problem with i2c.probe(id, address) is that AVR32 cannot send This is getting ridiculous. At this point I wish they kept the I2C engine from their 8 bit AVR MCU line. Besides not being able to to DMA transfers (although I'm not sure if this is still true for XMEGAs) it was much better than what they offer in the AVR32 IMO.
Do you happen to know what an I2C EEPROM does if you send it a single Hmmm, hard to say. It wouldn't be a problem for EEPROMs I think, but I don't know what's the case for other I2C devices.
Best, Bogdan _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
On 16 June 2011 19:20, Bogdan Marinescu <[hidden email]> wrote:
> In one of my applications I actually read the > whole content of a serial EEPROM (32KB (not Kb)) into a file in the > filesystem. Reading the whole data and writing it in one step is simply not > good enough because I'd need too much memory for the operation, so instead > I'm reading it in chunks of 256 bytes. Thanks. Yes, you would need to do the reading of the blocks at Lua level as separate I2C transactions as you describe. > I just feel that the I2C > interface introduces limitations that shouldn't be there ... The advantage of making the eLua APIs match the I2C protocol definition is that you can be sure to implement the API on any hardware, can be sure to drive any device, and be sure that users can only talk valid I2C language, however they call it. It's also a way of teaching learners exactly what valid I2C protocol means. I'm working on the assumption that modelling the eLua APIs on the I2C specification is the best way to guarantee that we will be able to drive all master interfaces and talk to all slave devices, including those we do not know, or that have not been produced yet. On one hand, the spec does say that I2C does not impose a limit on the amount of data present in one transfer. On the other, ir doesn't say that it's mandatory for a master to be able to handle infinite length transfers. > Absolutely. I'm not using EEPROM as an example because I want to model our > I2C platform interface after it, it's just an use case I'm quite familiar > with in practice and I can use it to detect limitations in our interface. So > far it's doing a pretty good job :) I confess that starting a 32-megabyte transfer in one function call, then reading the data of one packet in 256-bytes chunks with separate function calls is not a usage scenario that I had thought of. Here's another nightmare for you. I just found a device that eats infinite-length data packets for lunch. It's an 8-bit ADC/DAC device http://www.nxp.com/documents/data_sheet/PCF8591.pdf that can perform both analog-to-digital or digital-to-analog conversion in the same time it takes to transmit or receive one byte and it can send you an infinite amount of data, or you can send *it* an infinite amount of data in one I2C read or write packet, assuming that you can consume or generate it fast enough: one sample every 90us, i.e. every nine 100kHz bus clocks == 11,111 samples per second. To do audio, you'd have to be able to make a Lua-to-C-to-Lua transition in 90 us so as not have glitches in the output or miss samples on input. At 100 MHz CPU clock and 4 cycles per instruction, that's something like 250 instructions, which sounds possible in assembler. Could you make a round trip from the Lua interpreter to C and back in that sort of time and do something useful with the data? Would you want to? :) >> My own problem with i2c.probe(id, address) is that AVR32 cannot send >> empty data packets. > This is getting ridiculous. At this point I wish they kept the I2C engine > from their 8 bit AVR MCU line. Besides not being able to to DMA transfers > (although I'm not sure if this is still true for XMEGAs) it was much better > than what they offer in the AVR32 IMO. It gets worse. A different ADC instead http://www.ti.com/lit/gpn/ads7823 when you just send it a single zero data byte, that means "power up and convert 4 samples from analog to digital". I suppose, as it's a slave device, that one case is harmess, but what might other devices do? Anyway, there's nothing I can do about that. The only difference the AVR32 limitation makes to us is that it suggests adding i2c_master_probe( id, slave_address ) to the C platform interface, so that AVR32 can do it's brain-damaged thing sending a 0 byte, while allowing other platform can do something more healthy. If that were implemented at a higher level as send(id, address, NULL, 0, true), the AVR32 would have to either fail that always because it can't do it (making probe() unusable) or send a single zero data byte when the user asked for none. I'm not sure which is worse. I guess that's why they call it TWI, not I2C. Unfortunately, I have this to work with :( Is it too much to limit the data transfer size to the RAM you want to dedicate to one message? Implementing a multi-function stop-and-go interface frightens me. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Martin Guy |
Laurent
Given that the AVR32 TWI hardware is so limited in what it can do, I've decided to implement I2C by bit-banging the two pins so that it will be able to do all of I2C instead of the restricted subset that the hardware can handle. It also saves me from either having to convince Bogdan to be sensible, or having to make and maintain an incompatible fork of eLua, both of which are much more painful. I'm afraid that this leaves you on your own again. I can only suggest that you try one of: 1) see if you can modify your SDK's routines to split them into what the current API demands 2) do something like what I would have had to do if I had used the AVR32 TWI hardware: collect the sequence of start() address() stop() calls in static variables and then emit commands to the hardware when you have received enough of a sequence that it can perform. 3) Don't use the chip's I2C hardware and implement those primitives as a bit-banging interface. Sorry, and good luck. M _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
On Wed, Jun 22, 2011 at 5:28 PM, Martin Guy <[hidden email]> wrote:
> Laurent > > Given that the AVR32 TWI hardware is so limited in what it can do, > I've decided to implement I2C by bit-banging the two pins so that it > will be able to do all of I2C instead of the restricted subset that > the hardware can handle. OK, so I have to admit that I haven't followed every twist and turn of this, nor have I looked at the NXP hardware or driver implementation that you're discussing suggestions about below, but it strikes me that if we're going to have to bitbang i2c in order to make the eLua API work with the hardware modules on more than one platform then the API has got to change. Maybe what we should do in that situation is to branch it out into some sort of "restricted" and a "low level" API, I'm not sure. It sounded like some of the differences of opinion were around the idea of being able to read and write in chunks rather than doing it as a one-shot operation. The issue is that platforms like AVR32 can't do the chunked operations since the hardware expects the transaction to be described upfront? The read and write functions could probably work in both modes, with passed parameters indicating that the transaction shouldn't be closed yet or something similar? For platforms that don't support this as an option, and this would be documented as well, would return an error indicating that it's not a supported capability. We already have some precedent for this in the sense that for things like ADC only certain timers (or none) can be used as trigger sources. This functionality could be referred to as "extended" i2c support or something similar? Riffing on bogdan's example, maybe something like this: write( id, address, data, len, send_stop ) read( id, address, data, len, send_stop ) Where in this case send_stop is an optional parameter only supported for platforms where one can do an open-ended transaction, this would lead to a model like this for such multi-stage: write( id, address, data, len, 0 ) -- trying to not send a stop would give an error on platforms like avr32 write( id, -1, data, len, 0 ) -- repeat as needed, passing -1, or maybe nil in Lua indicates not to try sending the address again (attempting to call write with a non-valid address on non-"extended" platforms would result in an error write( id, -1, data, len, 1 ) -- end In lua the stop parameter could be an optional one, again specifically labelled as being part of "extended" support. I would generally be a fan of encapsulating as much functionality into a given Lua function call as possible anyways since looping and iterating in C code is much cheaper than looping in Lua. I don't hugely like having separate functions to spit the address out on the bus etc since that's yet more byte code that has to be executed every time the user starts an i2c operation. Does that seem more reasonable or have I missed part of this? > It also saves me from either having to > convince Bogdan to be sensible, or having to make and maintain an > incompatible fork of eLua, both of which are much more painful. I lost track of this discussion a little. I think that as a bottom line the API should be able to degrade well enough to work with the hardware that's available while incorporating a useful feature set for a high level language (reducing the amount of bytecode that has to be churned to get a task done, plus providing a reasonably friendly API). At the same time, I don't think the API has to be perfect, just useful for most of the cases where it is applied, unambiguous about what it's doing and just attractive enough so that when people look at it they think about getting use out of it rather than how ugly it is (there's more to it than these, but I think these are relevant to this case). I probably should have jumped in here and dug into more of the details to try and help hash this out a bit better, but I've been running a bit low on time and felt like reading up a bit on the platform and i2c spec before chiming in again. If we can, lets take this a few steps back and focus on hashing out something that will work for all of us. Best. -jsnyder _______________________________________________ eLua-dev mailing list [hidden email] https://lists.berlios.de/mailman/listinfo/elua-dev |
Free forum by Nabble | Edit this page |