kernelcode
Posts: 16
Joined: Tue Nov 22, 2011 3:47 pm

I2C (BSC) Automatically aborts on error?

Sun Jun 03, 2012 4:52 pm

This is a bit of a niche question - but maybe someone from Broadcom/with more knowledge could help?

I'm using Chris Boot's i2c driver, seems to work fine looking on an oscilloscope.
However, I'm using it to talk to an LCD which isn't quite i2c compliant - it will never ACK, instead the datasheet says you should just ignore the N/ACK bit.
This is OK, because the linux driver architecture allows for "protocol mangling," and I have (I think) modified Chris' driver to work with the I2C_M_IGNORE_NAK option.

The problem is, it looks like the BSC aborts the transaction anyway - the driver code happily ignores the error, but the scope trace shows the address is transmitted, then a NACK (as expected) and then a stop condition.
The stop is unexpected - as the transfer is several bytes long. The peripherals datasheet we have [1] indicates that the ERR bit in the status register is set to indicate a NACK condition (which my driver code ignores), however makes no mention of whether the hardware aborts a transaction in this case.

Hopefully I've actually got the software wrong, but does anyone know of this hardware "feature?"

[1] http://www.designspark.com/files/ds/sup ... CM2835.pdf

kernelcode
Posts: 16
Joined: Tue Nov 22, 2011 3:47 pm

Re: I2C (BSC) Automatically aborts on error?

Tue Jun 05, 2012 4:17 pm

For what it's worth I've managed a workaround. My application will eventually have an AVR connected to the i2c bus anyway, so I've stuck an attiny on there, sniffing all the i2c transactions.
If the transaction is directed at the LCD then it ACKs every byte for it.

If anyone else runs into this problem, here's the attiny2313 c code, maybe you can use the same solution :)

Code: Select all

#define F_CPU 8000000

#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>

#define MODE_IDLE    0 // Waiting for address
#define MODE_LCD     1 // Matched address
#define MODE_NOMATCH 2 // Non-matched address

// Tracks current position in sequence
#define STEP_0 0 // End of byte
#define STEP_1 1 // Start of byte

#define LCD_ADDR 0x74   // Address to match

uint8_t mode = 0;
uint8_t step = 0;

void i2c_init( void ) {
    DDRB = 0xA0;
    // Start condition interrupt, timer overflow interrupt, 2-wire mode with clock stretching on start and overflow
    USICR = (1 << USISIE) | (1 << USIOIE) | (3 << USIWM0) | (3 << USICS0);
    USIDR = 0xFF;
    PORTB = 0xA0;
}

int main(void) {
    _delay_ms(1000);
    i2c_init();
    sei();
    for (;;);
	return 0;
}

ISR(USI_START_vect) {
    USIDR = 0xFF; // Stay passive
    mode = MODE_IDLE;
    step = STEP_1;
    USISR = 0x8F; // Set counter = F and release SCL
}

ISR(USI_OVERFLOW_vect) {
    if (step == STEP_0) { // End of byte
        if (mode == MODE_IDLE) { // Looking for address
            uint8_t data = USIDR;
            if (data == LCD_ADDR) { // LCD Mode (just ACK every byte)
                mode = MODE_LCD;
            } else {
                mode = MODE_NOMATCH; // Not us - stay passive
            }
        }
        if (mode == MODE_LCD) {
            PORTB &= ~(0x20); // Generate ACK
            USIDR = 0xFF;
        } else {
            USIDR = 0xFF;
        }
        step = STEP_1;
        USISR = 0x4E; // Set counter = E and release SCL
    } else { // Start of Byte
        step = STEP_0;
        PORTB |= (0x20); // Set SDA HIGH (passive)
        USIDR = 0xFF;
        USISR = 0x40; // Set counter = 2 and release SCL
    }
}

nathanpust
Posts: 1
Joined: Tue Aug 21, 2012 2:40 am

Re: I2C (BSC) Automatically aborts on error?

Tue Aug 21, 2012 2:43 am

I am having the same problem with an LCD. Could you post the source that you produced? I would like to see what you tried (even if it didn't work).

Also, does anyone in the community know if the i2c on the raspberry pi supports "protocol mangling" on this type?

Return to “Interfacing (DSI, CSI, I2C, etc.)”