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!

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[].

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.

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.

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.