Forum: Mikrocontroller und Digitale Elektronik Probleme mit SRAM 23LCV1024


von Anon A. (anon1234)


Angehängte Dateien:

Lesenswert?

Hallo..
ich versuche mich gerade daran mit einem AT89S52 testweise Daten auf den 
den seriellen Baustein 23LCV1024 zu schreiben und danach wieder 
auszulesen.
Folgender Ablauf sollte hierfür eigentlich richtig sein:

Ablauf Schreiben :

  - WRITE : MODE REGISTER INSTRUCTION (00000001_b)
     - WRITE : BYTE MODE (00000000_b)
  - WRITE : WRITE DATA INSTRUCTION (00000010_b)
  - WRITE : Address
     - AddressByte1
     - AddressByte2
     - AddressByte3
  - WRITE : Data (1Byte)

Ablauf Lesen:

  - WRITE : READ DATA INSTRUCTION (00000011_b)
  - WRITE : Address
     - AddressByte1
     - AddressByte2
     - AddressByte3
  - READ : Data (1Byte)

Vor jedem Schreibe und Lese-Zyklus muss CS auf LOW gezogen werden (bzw. 
auf HIGH da der Pin invertiert ist), danach entsprechen wieder auf HIGH 
(bzw. auf LOW). Die Daten werden beim Schreiben in den Speicher jeweils 
bei der steigende Taktflanke übernommen und beim Lesen aus dem Speicher 
bei der fallenden Taktflanke herausgegeben. Ansonsten ist eigentlich 
alles recht trivial.

Allerdings habe ich jetzt mehrere male getestet und der Speicher gibt 
einfach keine Daten zurück. Ich habe das ganze auch mal mit dem 
Logikanalysator untersucht und bin eigentlich der Meinung, dass alles 
soweit richtig läuft, bis auf dass der Speicher das Byte halt nicht 
wieder auf SO legt.

Mein Code sieht folgendermaßen aus:
Ich nutze hierbei testweise die Adresse 00000000 00000000 00000000 und 
das Datenbyte 55h (01010101_b)
1
$include(at89s53.inc)
2
3
; p1.0 = NOT(CS) 
4
; p1.1 = SCK
5
; p1.2 = SI
6
; p1.3 = SO
7
; r7 = Buffer
8
9
main:
10
  clr p1.0        ; pull CS high  
11
  setb p1.0
12
  ;mov p2,#55h
13
  call writeByteMode
14
  call writeDataByteMode
15
  call readDataByteMode
16
  jmp main
17
  
18
writeByteMode:
19
  mov r7,#00000001b ; WRITE MODE REGISTER INSTRUCTION
20
  call write      ;
21
  mov r7,#00000000b   ; 0 0 = Byte Mode
22
  call write      ;
23
  clr p1.0          ; pull CS HIGH
24
  ret
25
26
writeDataByteMode:
27
  mov r7,#00000010b ; WRITE DATA INSTRUCTION
28
  call write
29
  mov r7,#00000000b
30
  call write
31
  call write
32
  call write
33
  mov r7,#55h
34
  call write
35
  clr p1.0  ; pull CS HIGH
36
  ret
37
  
38
readDataByteMode:
39
  mov r7,#00000011b ; READ DATA INSTRUCTION
40
  call write
41
  mov r7,#00000000b
42
  call write
43
  call write
44
  call write
45
  call read
46
  clr p1.0
47
  mov a,r7
48
  mov p2,a
49
  ret
50
51
; pull cs high after write
52
write:
53
  setb p1.0        ; pull CS LOW  
54
  mov r1,#8  
55
  write8BitsLoop:
56
    clr p1.1  ; SCK LOW
57
    mov a,r7
58
    rl a      ; rotate msb to lsb
59
    mov r7,a
60
    anl a,#00000001b  ; get lsb
61
    jz low_1
62
    high_1:
63
      setb p1.2
64
      jmp write_
65
    low_1:
66
      clr p1.2
67
      jmp write_
68
    write_:
69
      setb p1.1 ; SCK HIGH
70
      djnz r1,write8BitsLoop
71
    ret
72
    
73
; pull cs high after read    
74
read:
75
  setb p1.0        ; pull CS LOW  
76
  setb p1.1  ; SCK HIGH
77
  mov r7,#0h
78
  mov r1,#8  
79
  read8BitsLoop:
80
    clr p1.1  ; SCK LOW
81
    mov a,r7
82
    rl a
83
    jb  p1.3, high_2
84
    jnb p1.3, low_2
85
    high_2:
86
      orl a,#00000001b
87
      jmp read_
88
    low_2:
89
      orl a,#00000000b
90
    read_:
91
      setb p1.1 ; SCK HIGH
92
      mov r7,a
93
      djnz r1,read8BitsLoop
94
      ret
95
96
97
end

Das Datenblatt und meine Messung mit dem Logikanalysator hab ich 
angehängt..
Über jede Hilfe würde ich mich sehr freuen :)

Gruß
Anon123

von Anon A. (anon1234)


Lesenswert?

Momentan ist mein einziger Ansatz, dass der Pin SO beim Schreiben 
Hochohmig sein soll, laut Logikanalysator jedoch auf High liegt. (High 
ist der Default wert auf allen Pins beim AT89S52)
Allerdings habe ich keine Ahnung wie ich den Pin auf Hochohmig schalten 
kann..
ich glaube Sofwareseitig mit dem µC geht das garnich oder?

von Frank K. (fchk)


Lesenswert?

1. !CS
!CS separat steuern und in read/write nicht anfassen.
!CS muss vor jedem Befehl auf Low gesetzt werden, und nach jedem Befehl 
wieder auf High, sonst wird der Befehl nicht ausgeführt.

2. SCK
SCK am Anfang des Programms auf low setzen. Sicherstellen, dass SCK low 
ist, wenn der Zustand von !CS geändert wird. Im Ruhezustand ist SCK low.

3. Datenbits
erst Bit senden, dann SCK High, dann SCK low. Nicht anders. Setup-Zeiten 
beachten.

von Anon A. (anon1234)


Angehängte Dateien:

Lesenswert?

Frank K. schrieb:
> !CS muss vor jedem Befehl auf Low gesetzt werden, und nach jedem Befehl
> wieder auf High, sonst wird der Befehl nicht ausgeführt.

Mit Befehl meinst du aber nicht jedes Schreiben und lesen eines 
einzelnen Bytes, sondern so wie im Bild, dass ich angehängt hab:
 - !CS LOW
 - Dann alles was mit dem Schreiben zu tun hat
 - danach !CS wieder HIGH oder ;)

Die anderen Sachen probiere ich mal aus :)
Danke für deine Antwort!

: Bearbeitet durch User
von Frank K. (fchk)


Lesenswert?

Anon Anon schrieb:

> Mit Befehl meinst du aber nicht jedes Schreiben und lesen eines
> einzelnen Bytes, sondern so wie im Bild, dass ich angehängt hab:
>  - !CS LOW
>  - Dann alles was mit dem Schreiben zu tun hat
>  - danach !CS wieder HIGH oder ;)

"Befehl" umfasst das Befehlsbyte am Anfang und die dazugehörigen Daten.
Also:
!CS Low - Set Mode Command - Set Mode Data - !CS High -
!CS Low - Write Command - Write Address (3x) - Write Data - !CS High
...

von Anon A. (anon1234)


Lesenswert?

jaa genau das wollte ich sagen :)
dankeschön

von Anon A. (anon1234)


Lesenswert?

Frank K. schrieb:
> 3. Datenbits
> erst Bit senden, dann SCK High, dann SCK low. Nicht anders. Setup-Zeiten
> beachten.

bist du dir da sicher?
weil im Datenblatt etwas davon steht, dass die Daten beim Schreiben 
immer bei der steigenden Flanke übernommen werden.
1
3.2 Serial Output (SO)
2
The SO pin is used to transfer data out of the
3
23LCV1024. During a read cycle, data is shifted out on
4
this pin after the falling edge of the serial clock.
5
6
3.3 Serial Input (SI)
7
The SI pin is used to transfer data into the device. It
8
receives instructions, addresses, and data. Data is
9
latched on the rising edge of the serial clock.

von Frank K. (fchk)


Lesenswert?

Anon Anon schrieb:
> Frank K. schrieb:
>> 3. Datenbits
>> erst Bit senden, dann SCK High, dann SCK low. Nicht anders. Setup-Zeiten
>> beachten.
>
> bist du dir da sicher?
> weil im Datenblatt etwas davon steht, dass die Daten beim Schreiben
> immer bei der steigenden Flanke übernommen werden.

Ja, passt doch:
neues Bit senden
SCK HIGH
SCK LOW

und beim Lesen:
SCK HIGH
SCK LOW
neues Bit lesen

fchk

von Dirk K. (dekoepi)


Lesenswert?

Macht das "V" in der Typenbezeichnung etwas aus? Aus meinen Quellen:
1
// 23LC1024 SPI RAM instructions
2
#define RDMR  5  // Read Mode(Status) Register
3
#define WRMR  1  // Write Mode(Status) Register
4
#define READ  3  // Read Data
5
#define WRITE 2  // Write Data
6
7
// 23LC1024 modes
8
#define BYTE_MODE       0x00
9
#define PAGE_MODE       0x80
10
#define SEQUENTIAL_MODE 0x40
11
12
// 23LC1024 Instructions are sent this way: CS LOW, send command,
13
// (Read/write: send address,) send data, CS HIGH
14
15
// ...
16
17
  chip_select(RAM_bank);
18
19
  // Send WRITE MODE register command to chip
20
  spi1_tx(WRMR);
21
  spi1_tx(SEQUENTIAL_MODE);
22
  chip_deselect();
23
24
  chip_select(RAM_bank);
25
26
  // Send READ DATA command to chip
27
  spi1_tx(READ);
28
29
  // as default is sequential mode, address has to be sent only at start
30
  address = 0;
31
  spi1_tx((address>>16));   //send MSByte address first
32
  spi1_tx((address>>8));   //then send middle address uint8_t
33
  spi1_tx((address));      //send LSByte address
34
35
  // loop ....
36
  read_back=spi1_tx(0xFF);
37
  chip_deselect();

So klappt es bei mir.

: Bearbeitet durch User
von Anon A. (anon1234)


Angehängte Dateien:

Lesenswert?

Soo.. jetzt läuft es :)
Danke euch allen für eure Hilfe.
Ich habe noch mal eine neue Messung und den Programmcode angehängt.
Das einzige was mich noch stört, ist dass die LEDs, die die gelesenen 
Daten ausgeben gelegentlich falsche oder auch gar keine Werte anzeigen 
und das auch teilweise für ein zwei Sekunden am Stück..
Ich frage mich nun ob ich noch einen Programmierfehler gemacht habe, 
oder obs einfach an meinem Steckbrett und der relativ hohen Frequenz 
liegt (Wackelkontakt und co. ...)

Was meint ihr?

von Anon A. (anon1234)


Lesenswert?

Achso Port 0 ist SCK
      Port 1 ist SI
      Port 2 ist SO
      Port 3 ist !CS

von Anon A. (anon1234)


Angehängte Dateien:

Lesenswert?

Ich hab gerade festgestellt, dass ich damals den falschen code 
hochgeladen hab.
!cs muss nämlich genau anders herum angesteuert werden.
also hier nochmal der richtige code und ein screenshot vom logik 
analysator

Pin 0 NOT(CS)
Pin 1 SO
Pin 2 SI
Pin 3 SCK

von Anon A. (anon1234)


Angehängte Dateien:

Lesenswert?

Es gab noch einen Fehler im Taktsignal.
Zu beachten ist nämlich, dass
  - Bits, die in den Chip geschrieben werden sollen, immer bei der 
STEIGENDEN Flanke übernommen werden
  - Nits, die aus dem Chig gelesen werden sollen, immer bei der 
FALLENDEN Flanke vom Chip ausgegeben werden.

Der angehängte Quellcode sollte nun stimmen.

von alexis-mch (Gast)


Angehängte Dateien:

Lesenswert?

Falls jemand den 23LC1024 mit BASCOM programmiert, muss er den CS des 
RAMs auf einen separaten Pin des uP legen, denn der SS-Ausgang, der mit 
config spi = hard definiert wird, ergibt beim Read-Befehl eine 
Fehlfunktion.

SPI_RAM:                                                    'schreibt 
Test-Daten in das RAM und liest diese wieder aus

spi_ram_cs = 0                                              'CS true des 
SPI_RAM ohne SS-Pin (SPI = hard)
sdc_cmd(1) = &B00000001                                     'Mode 
Register Instruction
sdc_cmd(2) = &B00000000                                     'Byte 
Operation Mode
Spiout sdc_cmd(1), 2                                        '2 Bytes 
ausgeben
spi_ram_cs = 1                                              'CS false 
des SPI_RAM ohne SS-Pin (SPI = hard)

spi_ram_cs = 0                                              'CS true des 
SPI_RAM ohne SS-Pin (SPI = hard)
sdc_cmd(1) = &B00000010                                     'Write Data 
Instruction
sdc_cmd(2) = &B00000000                                     '1. Adress 
Byte MSB, first 7 Bits don't care
sdc_cmd(3) = &B00000000                                     '2. Adress 
Byte
sdc_cmd(4) = &B00000000                                     '3. Adress 
Byte LSB
sdc_cmd(5) = &B01010101                                     'Test Data
Spiout sdc_cmd(1), 5                                        '5 Bytes 
ausgeben
spi_ram_cs = 1                                              'CS false 
des SPI_RAM ohne SS-Pin (SPI = hard)

spi_ram_cs = 0                                              'CS true des 
SPI_RAM ohne SS-Pin (SPI = hard)
sdc_cmd(1) = &B00000011                                     'Read Data 
Instruction
sdc_cmd(2) = &B00000000                                     '1. Adress 
Byte MSB, first 7 Bits don't care
sdc_cmd(3) = &B00000000                                     '2. Adress 
Byte
sdc_cmd(4) = &B00000000                                     '3. Adress 
Byte LSB
Spiout sdc_cmd(1), 4                                        '4 Bytes 
ausgeben
                                                             'Achtung: 
hier wuerde der SS-Pin den CS kurz high schalten, was verboten ist
                                                             'deswegen 
muss dafür spi_ram_cs eingesetzt werden
Spiin temp_byte, 1                                          '1 Byte 
lesen
spi_ram_cs = 1                                              'CS false 
des SPI_RAM ohne SS-Pin (SPI = hard)

Locate 1,1
LCD "          ";                                           'LCD löschen
Locate 1,1
LCD hex(temp_byte);                                         'Data
Return

Der EAGLE-Stromlauf zeigt die Kombination des 23LC1024 und anderer 
externer Speichermedien mit einem Atmel MEGA1284.

von Uwe D. (monkye)


Lesenswert?

Ist zwar uralt, aber die Frage ist: In welchem Mode muss die Soft-SPI 
konfiguriert werden?

von Lukas J. (lukas_j838)


Angehängte Dateien:

Lesenswert?

Guten Abend,

leider muss ich das Thema mit dem SPI-RAM Baustein 23A1024/23LC1024 
nochmal aufgreifen. Folgendes Problem:

Für eine zeitkritische Anwendung möchte ich Daten, die ich zuvor in 
diesem RAM eingelegt habe möglichst schnell noch einmal auslesen. Dazu 
bietet sich der sequenzielle Auslesemodus an. Leider lese ich aber in 
diesem Modus immer nur das erste Byte, sprich das Byte der zuvor 
übermittelten Adresse aus, der Adresszeiger inkrementiert also nicht. 
Deswegen lese ich derzeit Byte für Byte nach der jeweiligen 
Adressübermittlung aus, was aber auf Dauer nicht die Lösung sein kann.

Anmerkung. Der SPI wird unter anderem auch für die Kommunikation mit 
einer SD-Karte genutzt, er funktioniert auch für das byteweise Schreiben 
in den RAM tadellos.

Hier der Code zur SPI-Konfiguration:
1
void init_SPI_1(){
2
    deSelectAllSlavesPeri();
3
    SPI1STATbits.SPIEN=0;
4
    SPI1CON1bits.DISSCK=0; // internal spi clock enabled
5
    SPI1CON1bits.DISSDO=0; // SDO pin used by SPI
6
    SPI1CON1bits.MODE16=0; // 8 bits communication
7
    
8
    SPI1CON1bits.MSTEN=1; // master mode
9
    
10
    SPI1CON1bits.CKP=0; // ruhezustand takt = LOW (ram) 
11
    SPI1CON1bits.SMP=0; // abtastung am Ende of data output time
12
    SPI1CON1bits.CKE=1; // steigende Flanke 
13
    
14
    // 20MHz 
15
    SPI1CON1bits.SPRE=0b101; // secondary 2:1
16
    SPI1CON1bits.PPRE=0b11; // primary 1:1
17
    
18
    SPI1CON2bits.FRMEN=0;
19
    SPI1CON2bits.SPIBEN=0; //enhanced mode disabled (Enhanced=1 : FIFO enable)
20
    SPI1BUF=0x00; // buffer to zero
21
    SPI1STATbits.SPITBF=0; // clear BF
22
    SPI1STATbits.SPIEN=1; // enable spi
23
    SPI1STATbits.SPITBF=0; // clear BF   
24
    
25
    transmit_SPI1(0xFF);
26
    
27
    waitus(10);
28
    SPI1STATbits.SPIEN=0;
29
    SPI1STATbits.SPIEN=1;  
30
}

Hier die Konfiguration des RAM-Bausteins:
1
void init_RAM(){  
2
    
3
    //POWER UP RULE
4
    CS_RAM=0;
5
    waitus(20);
6
    CS_RAM=1;
7
    
8
    // Set Mode to Sequential (default)
9
    CS_RAM=0;
10
    transmit_SPI1(RAM_MODE_WRITE); //0x01
11
    transmit_SPI1(0x00);// Set Byte-Mode
12
13
    CS_RAM=1;
14
    
15
    CS_RAM=0;
16
    transmit_SPI1(RAM_MODE_READ);//0x05
17
    transmit_SPI1(0x40); //Sequenzielles Lesen
18
   
19
    CS_RAM=1;
20
      
21
}

und die Auslesefunktion:
1
void Read_RAM(long adress, char data[], unsigned int n_bytes){
2
    long adresscut;
3
    char test[20];
4
    CS_RAM=0;
5
    transmit_SPI1(RAM_READ);
6
    
7
    //write Adress 3 bytes
8
    adresscut=((adress & 0xFF0000) >> 16);
9
    transmit_SPI1(adresscut);
10
    //
11
    adresscut=((adress & 0x00FF00) >> 8);
12
    transmit_SPI1(adresscut);
13
    //
14
    adresscut=((adress & 0x0000FF) >> 0);
15
    transmit_SPI1(adresscut); 
16
    
17
    int i;
18
    for(i=0;i<n_bytes;i++){
19
        data[i]=ExchangeSPI(0xFF);
20
        
21
        }  
22
    CS_RAM=1;
23
}

Wenn ihr noch mehr Code braucht, lasst es mich wissen. Das Projekt ist 
zu umfangreich um alles hochzuladen.

Vielen Dank für Eure Hilfe!

: Bearbeitet durch User
von foobar (Gast)


Lesenswert?

1
    // Set Mode to Sequential (default)
2
    CS_RAM=0;
3
    transmit_SPI1(RAM_MODE_WRITE); //0x01
4
    transmit_SPI1(0x00);// Set Byte-Mode
5
    CS_RAM=1;
6
    
7
    CS_RAM=0;
8
    transmit_SPI1(RAM_MODE_READ);//0x05
9
    transmit_SPI1(0x40); //Sequenzielles Lesen
10
    CS_RAM=1;
Hast du dir mal angeschaut, was du da machst?  Schaltest auf Byte-Mode 
und liest dann das Mode-Register nochmal aus.

von Lukas J. (lukas_j838)


Lesenswert?

Hallo foobar,

vielen Dank für deine schnelle Antwort.

Schande über mich! Du hast natürlich vollkommen Recht. Ich war der 
Meinung, dass ich ein Read-Mode und ein Write-Mode Register separat 
setzen muss. Ein genauerer Blick ins Datenblatt hätte das verhindern 
können.

Problem gelöst!:-)

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.