Forum: Mikrocontroller und Digitale Elektronik Anbindung eines I²S Audio-Codec


von Daniel K. (daniel_k80)


Lesenswert?

Hallo zusammen,

ich habe einen SSM2603 Audio-Codec an einem Linux-System und möchte den 
nun gerne über I²C konfigurieren.
Über I²C-Tools bekomme ich folgende Ausgabe
1
root@Zybo:/Software# i2cdetect -y -r 0
2
0 1 2 3 4 5 6 7 8 9 a b c d e f
3
00: -- -- -- -- -- -- -- -- -- -- -- -- --
4
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- -- -- --
5
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
6
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
7
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
8
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
9
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10
70: -- -- -- -- -- -- -- --

Jetzt habe ich mir ein Programm geschrieben um mir die Registerinhalte 
des Chips ausgeben zu lassen:
1
#include <string.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <unistd.h>
5
#include <linux/i2c-dev.h>
6
#include <sys/ioctl.h>
7
#include <sys/types.h>
8
#include <sys/stat.h>
9
#include <fcntl.h>
10
11
int main()
12
{
13
  int Counter = 0;
14
  int Bus_File;
15
  int Address = 0x1a;
16
  char *Bus = "/dev/i2c-0";
17
  char Buffer[10] = {0};
18
19
  if ((Bus_File = open(Bus, O_RDWR)) < 0) 
20
  {
21
      printf("Failed to open the i2c bus");
22
      exit(1);
23
  }
24
25
  if (ioctl(Bus_File, I2C_SLAVE, Address) < 0) 
26
  {
27
      printf("Failed to acquire bus access and/or talk to slave.\n");
28
      exit(1);
29
  }
30
31
  for(Counter = 0; Counter < 9; Counter++)
32
  {
33
    Buffer[0] = Counter;
34
    if (write(Bus_File, Buffer, 1) != 1) 
35
    {
36
        printf("Failed to write to the i2c bus.\n");
37
    }
38
39
        if (read(Bus_File, Buffer, 1) != 1) 
40
    {
41
      printf("Failed to read from the i2c bus.\n");
42
       } 
43
    else 
44
    {
45
      printf("Data %i %i\n", Counter, Buffer[0]);
46
    }
47
  }
48
49
  return 0;
50
}

Beim starten des Programmes bekomme ich jetzt aber nur

Data 0 151
Data 1 151
Data 2 151
Data 3 151
Data 4 151
Data 5 151
Data 6 151
Data 7 151
Data 8 151

ausgegeben. Der Wert 151 ist dabei der Defaultwert des 1. Registers, 
sprich ich lese wohl nur das 1. Register aus.
Aber warum?

Danke für die Hilfe!

: Verschoben durch User
von Clemens L. (c_l)


Lesenswert?

Daniel K. schrieb:
> ich lese wohl nur das 1. Register aus.
> Aber warum?

Laut Datenblatt will der SSM2603 beim Lesen ein "repeated start" haben 
(Start-Bit ohne vorheriges Stop-Bit).

Mit normalen write()/read()-Aufrufen ist das nicht möglich; du brauchst 
ioctl(I2C_RDWR).

von Georg A. (georga)


Lesenswert?

Normalerweise sollte zwischen dem Write der Registernummer und dem Lesen 
keine Stop-Condition sein, nur ein neues Start. Zu der simplen 
read-write-API finde ich keine Doku, die beschreibt ob/wie sie das mit 
Start/Stop eigentlich macht. Versuch mal die Beispiele mit den 
I2C_RDWR-ioctl, die sind explizit für sowas ausgelegt und man kann per 
Flags kontrollieren, was passiert.

Ist auch nicht viel komplizierter, hier ein Beispiel für Lesen von zwei 
Bytes:
1
u8 b[2];
2
u8 reg=42;
3
struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg, .len = 1 },
4
                          { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = 2 } };
5
6
struct i2c_rdwr_ioctl_data data;
7
data.msgs=msg;
8
data.nmsgs=2;
9
ret=ioctl(fd, I2C_RDWR, &data);

Die Daten stehen dann in b[].

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Lesenswert?

Danke für die Info :)
Genau sowas hatte ich gesucht. Ich werde es mir mal durchlesen und 
testen.

Edit: Hat vielleicht jemand einen Link zu einer Doku zur Hand?
Finde auf die Schnelle nichts.

: Bearbeitet durch User
von noonien (Gast)


Lesenswert?

Ich habe aus den Analog-Devices Modulen einen Alsa-SoC-Plattform Treiber 
für das Zybo zusammengesetzt. Das funktioniert recht gut inklusive 
alsamixer-Einbindung. Richtig aufgeräumt und getestet ist es aber noch 
nicht.

https://github.com/noonien-d/linux-Digilent-Dev/tree/zybo-audio

von Daniel K. (daniel_k80)


Lesenswert?

noonien schrieb:
> Ich habe aus den Analog-Devices Modulen einen Alsa-SoC-Plattform Treiber
> für das Zybo zusammengesetzt. Das funktioniert recht gut inklusive
> alsamixer-Einbindung. Richtig aufgeräumt und getestet ist es aber noch
> nicht.
>
> https://github.com/noonien-d/linux-Digilent-Dev/tree/zybo-audio

Hallo,

wo finde ich den den?
Weil das Board für das ich das machen möchte ist auch ein Zybo :)

von noonien (Gast)


Lesenswert?

Eigentlich müsste alles was den ssm260x betrifft in folgendem Patchset 
enthalten sein:

https://github.com/noonien-d/linux-Digilent-Dev/commit/977cde457c1667804ff83c3989fa9c67baafabf5

von Ferdinand S. (noonien) Benutzerseite


Lesenswert?

Ich habe für den ssm2603 mal ein einen eigenen Zweig aufgemacht, der 
Rest hat damit nicht viel zu tun:

https://github.com/noonien-d/linux-Digilent-Dev/tree/zybo-ssm2603

(ich kann den alten Link oben leider nicht korrigieren weil ich nicht 
angemeldet war)

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

ich habe mir nun mal etwas zusammen gebastelt:
1
#include <stdio.h>
2
#include <fcntl.h>
3
#include <errno.h>
4
#include <unistd.h>
5
#include <stdlib.h>
6
#include <string.h>
7
#include <linux/i2c.h> 
8
#include <linux/i2c-dev.h>
9
#include <sys/ioctl.h>
10
11
#define SSM2603_Addr  0x1a
12
13
int I2C_ReadRegister(int fd, char Address, char Register);
14
15
int main()
16
{
17
  int Bus_File;
18
  char *Bus = "/dev/i2c-0";
19
20
  int Counter = 0;
21
22
  if ((Bus_File = open(Bus, O_RDWR)) < 0) 
23
  {
24
      printf("Failed to open the i2c bus");
25
      exit(1);
26
  }
27
28
  for(Counter = 0; Counter < 9; Counter++)
29
  {
30
    I2C_ReadRegister(Bus_File, SSM2603_Addr, Counter);
31
    printf("-----\n");
32
  }
33
34
  return 0;
35
}
36
37
int I2C_ReadRegister(int fd, char Address, char Register)
38
{
39
  char Buffer[2];
40
  struct i2c_msg I2C_Nachricht[] = {   { .addr = Address, .flags = 0, .buf = &Register, .len = 1 },
41
            { .addr = Address, .flags = I2C_M_RD, .buf = Buffer, .len = 2 } 
42
          };
43
  struct i2c_rdwr_ioctl_data Data = { I2C_Nachricht, 2 };
44
45
  ioctl(fd, I2C_RDWR, &Data);
46
  
47
  printf("LSB: %i\n", Buffer[0]);
48
  printf("MSB: %i\n", Buffer[1]);
49
  return 1;
50
}

Die Ausgabe sieht auch besser aus, nur bekomme ich jetzt folgendes 
ausgegeben:
1
LSB: 151
2
MSB: 0
3
-----
4
LSB: 0
5
MSB: 151
6
-----
7
LSB: 151
8
MSB: 0
9
-----
10
LSB: 0
11
MSB: 121
12
-----
13
LSB: 121
14
MSB: 0
15
-----
16
LSB: 0
17
MSB: 121
18
-----
19
LSB: 121
20
MSB: 0
21
-----
22
LSB: 0
23
MSB: 10
24
-----
25
LSB: 10
26
MSB: 0
27
-----

Das ist auch nicht ganz richtig. Warum tauscht er die Werte? 
Normalerweise müssen die Werte ja immer an der selben Stelle stehen.

Edit:
Fehler gefunden. Musste die Adresse ein Bit schieben - hab ich im 
Protokoll übersehen.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.