[En-Nut-Discussion] TWI and Lua problem
andre at riesberg-net.de
Sun Apr 10 16:38:20 CEST 2011
Bernd Walter schrieb:
> On Sun, Apr 10, 2011 at 09:32:11AM +0200, Andre Riesberg wrote:
>> Hello all,
>> I use NutOS 4.9.10 on a board like EIR with a SAM7S CPU. I use a big
>> display board with 72 LED using four LTC3220 LED driver and a PCA9546A
>> I2C multiplexer. Everything works fine when I access the devices from c
>> code. If I try to access the device from a Lua script (I had written a
>> Lua function wrapper for TwMasterTransact) I run into problems. After
>> some bytes (5 to 15) I see a too short clock pulse. Normally the clock
>> pulse is 100µs long, both high and low part. The too short low pulse is
>> only 0.5µs long. This equivalent to a frequency of 1MHz and much too
>> fast for the I2C devices I use.
>> If I call the Lua wrapper function directly from c, It works fine. It
>> fails only together with Lua.
>> I have higher the stack space of the Lua thread. Same result.
>> I check heap memory with NUTMEM_GUARD and NUTDEVICE_HEAP, everything is ok.
>> Nobody change the port pins (SDA, SCL).
> This is not specificly about your short impulse, but there is an
> annoying point about the TWI controller, which is worth mentioning.
> You start a transfer with an internal addressing setup.
> So in fact it does a start, addresses for writing writes a few bytes,
> then depending on the intended data direction it does a restart for
> reading or stays in writing.
> This all happens without further software intervention.
> Now for transfering data you need to read/write the data register.
> DMA as in most other IO-controller is not available.
> Normaly you would expect that if you don't read/write the register the
> clock just stops to pause transmission and that's it, but that's not
> true for that hardware.
> What the TWI controller does is issuing a stop and when you finally
> access the data register it issues a start again.
> This should be true at least for all the single-master-only controllers
> as in RM9200, most SAM7S, SAM7X.
> The SAM7S16 and SAM7S161 at least have an updated TWI with master/slave
> support - I don't know the details, since the controller wasn't
> attractive for me.
> Maybe if you are just slightly out of timing for register access you
> get such a glitch...
> You should try a slower clock speed for verification.
> That said: I've never used the NutOS twi code, so maybe such conditions
> are completely avoided by software design.
> About the multiplexer in general - they have a very high resitive
> on mode, which has a major influence if you have a high wire capacity.
> I don't think this can explain your glitch, but might change the
> symptoms of short glitches.
I'd make more test and found some interesting things. First, I use the
function TwMasterTransact to send an address an two data bytes. The
function TwMasterRegWrite should be the better one. But I am not sure if
will fix this issue.
With an digital scope I see the start bit was send, then the address
byte, next the first data byte. And next I see the stop bit, but this is
wrong. Now I see the second data byte with the glitch.
In the data sheet under "Master Transmitter Mode" I found:
"When an acknowledge is detected, the TXRDY bit is set until a new write
in the TWI_THR. When no more data is written into the TWI_THR, the
master generates a stop condition to end the transfer."
The address byte and the first data byte are send in the function
TwMasterTransact, the second data byte is put in the buffer to send it
in the TwInterrupt function. Every thing is fine so long the interrupt
will be handled fast enough. If the TWI_THR is not filled fast enough
the stop bit is send. But the interrupt is handle and (too late) the
byte is written to TWI_THR. I think this confuses the TWI hardware and
produces the glicht(es).
Until now, I do not found a way to suppress the stop bit until the
interrupt is handled.
I think this is a weakness in the TWI hardware. If you have high speed
on the TWI bus or a complex system with disabled interrupts, the
interrupt driven TWI handling will not work. The async TWI bus has now
some synchron aspects and this is worse!
This behavior fits good my application. If I send the data before all
the threads are running, it works. If the Lua thread and all the other
threads are running it fails.
More information about the En-Nut-Discussion