I2C from Raspberry Pi to ATmega: java.io.IOException: Error writing to /dev/i2c-1 at address 0x40. Got -20001.

285 views
Skip to first unread message

fmbsg-...@yahoo.de

unread,
Apr 4, 2014, 4:21:50 PM4/4/14
to pi...@googlegroups.com
Hi everybody,
I try to connect a Pi to a uC on a breadboard via I2C (aka TWI). Pi is running Java with Pi4J (within Eclipse started with sudo) and acts as I2C-Master. Far distant goal is to have the uC to act as sensor and to deliver values on demand of the hi-level-language controlled Pi. The "business logic" should stay in the Pi. Atmega on the breadboard is connected to 8 LED on port D to show, what's happening inside.

OK, here is the code in the ATmega (provided by Mr. Erfurt with slightly changes by me):
; TWI I2C SLAVE                    
; 10/2005                        
; Bernhard.Erfurt@gmx.de        
;                                
; TAKT=1.0 MHZ                    
;                                
.include "m8def.inc"


; TWI Slave Receiver Codes
.equ TW_SR_SLA_ACK            = 0x60; x60    01100000 (SLA+W wurde empfangen-ACK wurde zurückgesendet)                                                    
.equ TW_SR_ARB_LOST_SLA_ACK = 0x68; x68    01101000 (Arbitration verloren in SLA+R/W als MASTER;  SLA+W wurde empfangen;  ACK wurde zurückgesendet        
.equ TW_SR_GCALL_ACK          = 0x70; x70    01110000 (General call address wurde empfangen;  ACK wurde zurückgesendet                                    
.equ TW_SR_ARB_LOST_GCALL_ACK    = 0x78; x78    01111000 (Arbitration verloren in SLA+R/W als MASTER;General call address wurde empfangen; ACK wurde zurückgesendet
.equ TW_SR_DATA_ACK          = 0x80; x80    10000000 (die vorher adressierten (SLA+W) Daten wurden empfangen;  ACK wurde zurückgesendet                    
.equ TW_SR_DATA_NACK          = 0x88; x88    10001000 (die vorher adressierten (SLA+W) Daten wurden empfangen; ACK wurde nicht zurückgesedet                
.equ TW_SR_GCALL_DATA_ACK   = 0x90; x90    10010000 (die vorher adressierten (General call) Daten wurden empfangen;  ACK wurde zurückgesendet            
.equ TW_SR_GCALL_DATA_NACK  = 0x98; x98    10011000 (die vorher adressierten (General call) Daten wurden empfangen;  ACK wurde nicht zurückgesendet    
.equ TW_SR_STOP                = 0xA0; xA0    10100000 (STOP wurde empfangen, oder wiederholter Start)                                                    
; TWI Slave Transmitter Codes
.equ TW_ST_SLA_ACK            = 0xA8; xA8 10101000 (SLA+R wurde empfangen; ACK wurde zurückgesendet)                                                
.equ TW_ST_ARB_LOST_SLA_ACK = 0xB0; xB0 10110000 (Arbitration verlor SLA+R/W als MASTER, ACK wurde zurückgesendet)                                
.equ TW_ST_DATA_ACK          = 0xB8; xB8 10111000 (TWDR ist übertragen worden;  ACK ist empfangen worden                                            
.equ TW_ST_DATA_NACK          = 0xC0; xC0 11000000 (TWDR ist übertragen worden;  ACK ist NICHT empfangen worden                                    
.equ TW_ST_LAST_DATA          = 0xC8; xC8 11001000 (Letztes Datenbyte in TWDR ist übertragen worden (TWEA = "0");  Ack ist empfangen worden        
.equ TW_NO_INFO                = 0xF8; xF8 11111000 (Keine relevanten Zustandinformationen vorhanden;  TWINT = "0" keine TWDR-Tätigkeit            
.equ TW_BUS_ERROR            = 0x00; x00 00000000 (Bus-Error wegen ungültige STARToder STOP BEDIgung; keine TWDR-Tätigkeit                        

; TWI SLAVE EINSTELLUNGEN
.equ TWI_SLAVE_ADRESSE        = 0x40; eigene SLAVE ADRESSE 1...127            
.equ TWI_GENERAL_CALL_enable    = 1   ; 1=General Call enabled / 0=disabled    
; REGISTER
.def DATA=R15

.def TEMP = R16
.def TEMP1= R17
.def TEMP2= R18
.def TEMP3= R19
.def TEMP4= R20


.cseg                    ;Beginn eines Code-Segmentes
.org 0                    ;Startadresse=0

rjmp RESET            
; Reset Handler                          
reti
;rjmp EXT_INT0   ; IRQ0 Handler                      
reti
;rjmp EXT_INT1   ; IRQ1 Handler                      
reti
;rjmp TIM2_COMP  ; Timer2 Compare Handler            
reti
;rjmp TIM2_OVF   ; Timer2 Overflow Handler          
reti
;rjmp TIM1_CAPT  ; Timer1 Capture Handler            
reti
;rjmp TIM1_COMPA ; Timer1 CompareA Handler          
reti
;rjmp TIM1_COMPB ; Timer1 CompareB Handler          
reti
;rjmp TIM1_OVF   ; Timer1 Overflow Handler          
reti
;rjmp TIM0_OVF   ; Timer0 Overflow Handler          
reti
;rjmp SPI_STC    ; SPI Transfer Complete Handler    
reti
;rjmp USART_RXC  ; USART RX Complete Handler        
reti
;rjmp USART_UDRE ; UDR Empty Handler                
reti
;rjmp USART_TXC  ; USART TX Complete Handler        
reti
;rjmp ADC        ; ADC Conversion Complete Handler  
reti
;rjmp EE_RDY     ; EEPROM Ready Handler              
reti
;rjmp ANA_COMP   ; Analog Comparator Handler        
rjmp TWSI            
; Two-wire Serial Interface Handler
reti
;rjmp SPM_RDY    ; Store Program Memory Ready Handler


RESET
:                        
   
;STACK initialisieren        
    ldi temp
, LOW(RAMEND)
   
out SPL, temp
    ldi temp
, HIGH(RAMEND)
   
out SPH, temp
; PORT D all Output
    ldi temp
, 0b11111111
   
out DDRD, temp
   
out PORTD,temp
; PORT C all input, except C3 (=Error Indicator)    
    ldi temp
, 0b00001000
   
out DDRC,temp
    sbi PORTC
,3
; TWI INITIALISIERUNG        
    rcall TWI_INI
; STARTWERTE                
    clr DATA
; alle Interrupts freigeben
    sei


LOOP
:
rjmp LOOP
; #############################################################################


; TWI INTERRUPT-Routine        
TWSI
:
    push temp          
; temp auf dem Stack sichern          
   
in TEMP,SREG        ; Einlesen des SREG
    push TEMP            
; Schreiben von  SREG  im Stack (KOPIE)
;-------
   
in temp, TWSR        ; Status-Register abfragen                        
    andi temp
, 0xF8        ; mask Bit0...2 (Prescaler und Reserve-Bit)

    ldi temp1
, 170
   
out PORTD,temp1        ; show start pattern (10101010)
    rcall wait_1s
   
out PORTD,temp        ; show TWSR
    rcall wait_1s
    rcall wait_1s
    rcall wait_1s
    ldi temp1
, 255
   
out PORTD,temp1        ; turn off all LED
   
    cpi temp
, TW_SR_SLA_ACK                ; x60    
    breq TWSI_TW_SR_SLA_ACK
    cpi temp
, TW_SR_ARB_LOST_SLA_ACK    ; x68    
    breq TWSI_TW_SR_ARB_LOST_SLA_ACK
    cpi temp
, TW_SR_GCALL_ACK            ; x70    
    breq TWSI_TW_SR_GCALL_ACK
    cpi temp
, TW_SR_ARB_LOST_GCALL_ACK    ; x78    
    breq TWSI_TW_SR_ARB_LOST_GCALL_ACK
    cpi temp
, TW_SR_DATA_ACK             ; x80    
    breq TWSI_TW_SR_DATA_ACK        
    cpi temp
, TW_SR_DATA_NACK             ; x88    
    breq TWSI_TW_SR_DATA_NACK
    cpi temp
, TW_SR_GCALL_DATA_ACK      ; x90    
    breq TWSI_TW_SR_GCALL_DATA_ACK  
    cpi temp
, TW_SR_GCALL_DATA_NACK        ; x98    
    breq TWSI_TW_SR_GCALL_DATA_NACK
    cpi temp
, TW_SR_STOP               ; xA0    
    breq TWSI_TW_SR_STOP          
;    
    ldi temp1
, 85
   
out PORTD,temp1        ; show transmitter pattern (01010101)
    rcall wait_1s
    ldi temp1
, 255
   
out PORTD,temp1        ; turn off all LED
    cpi temp
, TW_ST_SLA_ACK               ; 0xA8    
    breq TWSI_TW_ST_SLA_ACK    
    cpi temp
, TW_ST_ARB_LOST_SLA_ACK    ; 0xB0    
    breq TWSI_TW_ST_ARB_LOST_SLA_ACK
    cpi temp
, TW_ST_DATA_ACK             ; 0xB8    
    breq TWSI_TW_ST_DATA_ACK
    cpi temp
, TW_ST_DATA_NACK             ; 0xC0    
    breq TWSI_TW_ST_DATA_NACK
    cpi temp
, TW_ST_LAST_DATA             ; 0xC8    
    breq TWSI_TW_ST_LAST_DATA
    cpi temp
, TW_NO_INFO               ; 0xF8    
    breq TWSI_TW_NO_INFO
    cpi temp
, TW_BUS_ERROR               ; 0x00    
    breq TWSI_TW_BUS_ERROR
    rjmp TWSI_TW_BUS_ERROR            
; nicht behandelte Status-Zustände    

; SLAVE RECEIVER                
TWSI_TW_SR_SLA_ACK
:                ; x60    01100000 (SLA+W wurde empfangen-ACK wurde zurückgesendet)
    cbi PORTD
,0
    rjmp TWSI_w
TWSI_TW_SR_ARB_LOST_SLA_ACK
:    ; x68    01101000 (Arbitration verloren in SLA+R/W als MASTER;  SLA+W wurde empfangen;  ACK wurde zurückgesendet
    cbi PORTD
,1
    rjmp TWSI_w
TWSI_TW_SR_GCALL_ACK
:            ; x70    01110000 (General call address wurde empfangen;  ACK wurde zurückgesendet        
    cbi PORTD
,2
    rjmp TWSI_w
TWSI_TW_SR_ARB_LOST_GCALL_ACK
:    ; x78    01111000 (Arbitration verloren in SLA+R/W als MASTER;General call address wurde empfangen; ACK wurde zurückgesendet
    cbi PORTD
,3
    rjmp TWSI_w
TWSI_TW_SR_DATA_ACK
:            ; x80    10000000 (die vorher adressierten (SLA+W) Daten wurden empfangen;  ACK wurde zurückgesendet    
    cbi PORTD
,4
   
in DATA, TWDR        ; DATA
    rjmp TWSI_w
TWSI_TW_SR_DATA_NACK
:              ; x88    10001000 (die vorher adressierten (SLA+W) Daten wurden empfangen; ACK wurde nicht zurückgesedet
    cbi PORTD
,5
    rjmp TWSI_w
TWSI_TW_SR_GCALL_DATA_ACK
:        ; x90    10010000 (die vorher adressierten (General call) Daten wurden empfangen;  ACK wurde zurückgesendet    
    cbi PORTD
,6
    rjmp TWSI_w
TWSI_TW_SR_GCALL_DATA_NACK
:        ; x98    10011000 (die vorher adressierten (General call) Daten wurden empfangen;  ACK wurde nicht zurückgesendet    
    cbi PORTD
,7
    rjmp TWSI_w
TWSI_TW_SR_STOP
:                ; xA0    10100000 (STOP wurde empfangen, oder wiederholter Start)
    cbi PORTD
,0
    cbi PORTD
,1
    rjmp TWSI_w

;    SLAVE TRANSMITTER        
TWSI_TW_ST_SLA_ACK
:                ; xA8     10101000 (SLA+R wurde empfangen; ACK wurde zurückgesendet)        
    cbi PORTD
,0    
    OUT TWDR
, DATA        ; DATA
    rjmp TWSI_w
TWSI_TW_ST_ARB_LOST_SLA_ACK
:    ; xB0     10110000 (Arbitration verlor SLA+R/W als MASTER, ACK wurde zurückgesendet)    
    cbi PORTD
,1
    rjmp TWSI_w
TWSI_TW_ST_DATA_ACK
:            ; xB8    10111000 (TWDR ist übertragen worden;  ACK ist empfangen worden
    cbi PORTD
,2    
    OUT TWDR
, DATA        ; DATA
    rjmp TWSI_w
TWSI_TW_ST_DATA_NACK
:            ; xC0    11000000 (TWDR ist übertragen worden;  ACK ist NICHT empfangen worden
    cbi PORTD
,3    
    OUT TWDR
, DATA        ; DATA
    rjmp TWSI_w
TWSI_TW_ST_LAST_DATA
:            ; xC8    11001000 (Letztes Datenbyte in TWDR ist übertragen worden (TWEA = "0");  Ack ist empfangen worden
    cbi PORTD
,4    
    rjmp TWSI_w
TWSI_TW_NO_INFO
:                ; xF8    11111000 (Keine relevanten Zustandinformationen vorhanden;  TWINT = "0" keine TWDR-Tätigkeit
    cbi PORTD
,5    
    rjmp TWSI_w
TWSI_TW_BUS_ERROR
:                ; x00    00000000 (Bus-Error wegen ungültige STARToder STOP BEDIgung; keine TWDR-Tätigkeit
    rcall TWI_ERROR    
    rjmp TWSI_w

;-------
TWSI_w
:    
   
   
;clear TWINT-Flag ((logisch 1)    
    ldi temp
, 1<<TWINT|1<<TWEA|1<<TWEN|1<<TWIE
   
out TWCR,temp

    pop TEMP            
; LESEN von SREG vom STACK (KOPIE)
   
out SREG,TEMP        ; Wiederherstellen von SREG      
    pop temp            
; temp wiederherstellen                    

reti
; #############################################################################


TWI_INI
:
   
; TWI TWAR (nur SLAVE)    Adress-Register        
    ldi temp
,(TWI_SLAVE_ADRESSE<<TWA0 | TWI_GENERAL_CALL_ENABLE<<TWGCE)
   
out TWAR,temp
   
; TWI TWCR Control-REGISTER    
    ldi temp
,(1<<TWINT|1<<TWEA|0<<TWSTA|0<<TWSTO|0<<TWWC|1<<TWEN|1<<TWIE)
   
out TWCR,temp
ret
; #############################################################################


TWI_ERROR
:

    cbi PORTC
,3

; TWI STOP                
    ldi r16
, (1<<TWINT)|(1<<TWEN)|(1<<TWSTO)
   
out TWCR, r16
; TWI aus                
    ldi r16
, (0<<TWEN)
   
out TWCR, r16
; TWI INITIALISIERUNG    
     rcall TWI_INI
   
    rcall wait_1s
   
    sbi PORTC
,3
ret
; #############################################################################


; Wait for TWINT Flag set.
TWI_TWINT_wait
:
   
in temp, TWCR
    sbrs temp
, TWINT
    rjmp TWI_TWINT_wait
ret
; #############################################################################


WAIT_1s
:
    push temp1          
; temp1 auf dem Stack sichern          
    push temp2          
; temp2 auf dem Stack sichern          
    push temp3          
; temp3 auf dem Stack sichern          

;------------
    ldi    temp3
,31  ;1MHz=5, 6=31, 8=41
    clr temp2
    clr    temp1            
wait1s_w
:    
    dec    temp1
    brne    wait1s_w
    dec    temp2        
    brne    wait1s_w
    dec    temp3
    brne    wait1s_w
;------------
    pop temp3            
; temp3 wiederherstellen                    
    pop temp2            
; temp2 wiederherstellen                    
    pop temp1            
; temp1 wiederherstellen                    
ret


And here is the Java code of  Pi:
import java.io.*;

import com.pi4j.io.i2c.*;


public class TwiTest {

   
/**
     * @param args
     */

   
public static void main(String[] args) {
       
TwiTest tt = new TwiTest();
       
try {
            tt
.run();
       
} catch (Exception e) {
            e
.printStackTrace();
       
}
   
}
   
   
void run() throws Exception {
       
System.out.println("start");
       
final I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
       
System.out.println("got bus");
        I2CDevice device
= bus.getDevice(0x40);
       
System.out.println("got device");
       
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
       
String str = "";
       
while (str != null) {
         
System.out.print("Number?> ");
          str
= in.readLine();
         
byte b = Byte.parseByte(str);
          device
.write(b);
         
System.out.println(b + " written");
         
int i = device.read();
         
System.out.println(i + " read");
       
}
   
}
}


Now, what happens?  When executing the line device.write(b); following happens on the breadboard:
a) the start pattern shows up indicating that general communication seems to work
b)
TW_SR_SLA_ACK (0X60) shows up, which seems correct to me
c) 0xFE shows up, which seems also to be correct, since it indicates the entry point of the SR_SLA_ACK-routine
everything looks fine on the uC-side, but in parallel i receive

java.io.IOException: Error writing to /dev/i2c-1 at address 0x40. Got -20001.
at com.pi4j.io.i2c.impl.I2CDeviceImpl.write(I2CDeviceImpl.java:72)
at TwiTest.run(TwiTest.java:32)
at TwiTest.main(TwiTest.java:14)

on the Java side. My example fails on the frst write. I tried a lot, but that problem stays.

Q1: What am I doing wrong?
Q2: Where is the list of possible error codes, containing -20001?

Any hints appreciated
kind regards
F..

Message has been deleted

fmbsg-...@yahoo.de

unread,
Apr 27, 2014, 2:08:01 PM4/27/14
to pi...@googlegroups.com
Gordon from Pi4J gave me a hint, which nearly solved the problem. The wait_1_second-calls in the assembler-call created clockstretching issues on the bus. Eliminating all these wait-calls gives a proper and reproducable communication in both directions.

The only issue, that's now open is a locked Hi-Byte...very strange. I put the value to be transmitted on LEDs straight before transmission to see it. It's definitly a Zero or a 3 or whatever. But the value, which is received by Pi has the hi-Byte always set: 0 becomes 128, 3 becomes 131, 127 becomes 255 ---- 128 stays 128, 150 stays 150 and so on
Absolutely reproducable, no some time-to-time-error.

Anybody any idea, what might set the hi-Byte ?

Kind regards
F..
Reply all
Reply to author
Forward
0 new messages