Forum: Mikrocontroller und Digitale Elektronik SPI 23LCV512 / 23LCV1024 ATMega328 oder ATtiny 2313


von Dominik V. (Firma: TBV) (d190979v)


Lesenswert?

Hallo zusammen,
für ein Testprojekt habe ich mir den Microchip 23LCV* (seriellen SDRAM) 
bestellt.
Da ich über diese Bauteile im Forum null Einträge gefunden habe ein 
kurzes Intro:
Die Chips gibt es u.a. im handlichen PDIP-8 Format und in verschiedenen 
Größen, ich habe die 512kbit (64kb) und 1Mbit (128kb) Varianten 
bestellt.
Die CHIPS werden über SPI angesprochen:
MODE 8bit ADRESSE 16/24bit DATEN 8bit (BYTE Operation Mode)
Die Maximale Frequenz liegt bei 20MHz und die Spannungsversorgung 2,5 
bis 5,5 Volt.
Diese spezielle Ausführung unterstützt eine Backup-Stromversorgung um 
den Speicherinhalt zu erhalten. Obwohl ich für dieses Projekt die 
Backup-Versorgung nicht brauche, scheinen die Chips ohnehin eine bessere 
Lösung für Projekte, wo sonst der EEPROM alle paar Wochen kaputt 
geschrieben ist. Abgesehen davon waren die anderen Typen ohne Backup zum 
Teil nicht lieferbar und nur ein paar 10Cent billiger.
Nun aber zum Thema: Die Speicher sollen als externer FIFO (Byte) 
herhalten.
Die Taktfrequenz des Prozessors wird bei 18,432 MHz liegen und es sind, 
wer hätte es gedacht, 11520 Bytes/sec zu speichern (wird ggf. noch 
verdoppelt). Damit liegen zwischen den Schreibzyklen 1600 Systemtakte, 
innerhalb dieser Takte muss natürlich (mindestens) dieselbe Menge an 
Bytes auch wieder aus dem Speicher geholt werden. Obwohl mir der 128kb 
Speicher für die Anwendung besser gefällt sind pro Schreib-Lesezyklus 2 
Bytes mehr zu übertragen (Adresslänge), hier ist der 64kb Speicher klar 
ökonomischer, da ich nur grob überschlagen habe, habe ich beide Tyoen 
bestellt, zur Not kommen 2 64er an den Bus.
Das restliche Programm wird nur aus einfachen mathematischen Funktionen, 
Port-Ausgaben und der Kommunikation via. USART bestehen, beides können 
ATMEGA328 und
der TINY2313 in derselben Geschwindigkeit. Jedoch bin ich mir aus 
mangelnder Erfahrung bzgl. des SPI unsicher. Der Mega hat hierfür eine 
vollwertige SPI-Schnittstelle, der Tiny "nur" das USI. Wie wirkt sich 
dies
auf die Prozessorauslastung aus? Machen es beide in "Hardware" oder nur 
der Mega?
Noch eine weitere Frage (eigentlich die gleiche):
Beim 512 er muss ich pro Byte schreiben/lesen 64bit übertragen
-> 11520x64 = 737280 bit/s
-> 1/25 F_CPU (rechnerisch)
Beim 1024 er muss ich pro Byte schreiben/lesen 80bit übertragen
-> 11520x80 = 921600 bit/s
-> 1/20 F_CPU (rechnerisch)
also wir der SPI in jedem Falle mit 1/16 F_CPU arbeiten müssen.
Ist es realistisch zu erwarten, das da noch ein "Echtzeit"-Programm 
parallel laufen kann?
(Falls nicht hat der Chip ja noch 2 andere Modi ;-) )

Gruß Dominik

: Bearbeitet durch User
von Dirk K. (dekoepi)


Lesenswert?

Hilft dir das hier als Antwort?
http://forum.arduino.cc/index.php?topic=225052.msg1658174#msg1658174

Ist gleich Sample-Code für ATmega328 mit bei, wie du den Speicher 
ansprichst. (Habe den 1MBit.) Geht ordentlich was durch, weit mehr als 
11 kByte/s.

Edit: Grade gesehen, du willst Byte für Byte schreiben/lesen und jedes 
mal mit Adresse ansprechen. Mit solch einem Setup und den 
Arduino-Libraries bin ich etwa auf 8 kByte/s gekommen. Vielleicht lässt 
sich da ein wenig durch direkte µC-Programmierung rausholen oder durch 
Gruppierung mit einem kleinen Puffer.

: Bearbeitet durch User
von Frank K. (fchk)


Lesenswert?

Ich denke, Dein Systemdesign ist ziemlich auf Kante genäht.

Ich empfehle Dir einen dsPIC33EP512GP502 oder einen PIC32MX250F128B, 
beides auch 28 Pinner, mit 16 Bit/70 MHz/48k bzw 32Bit/50MHz/32k RAM 
intern. Der große Vorteil ist, dass diese Prozessoren DMA-Controller 
eingebaut haben, die Daten von/zu einer Peripherieeinheit ohne 
Prozessorhilfe quasi im Hintergrund übertragen können. Das und der große 
interne Speicher vereinfachen vieles. Außerdem hast Du eine erheblich 
höhere Prozessorleistung, und das alles für nur 2€ mehr.

fchk

von Dominik V. (Firma: TBV) (d190979v)


Lesenswert?

Hi,

Dirk K. schrieb:
> Hilft dir das hier als Antwort?
> http://forum.arduino.cc/index.php?topic=225052.msg1658174#msg1658174

ja, das sieht auf jeden Fall schon einmal vielversprechend aus, leider 
habe
auf diesem Rechner keinen gescheiten Editor und habe die C-Datei nur als 
Zeichenwolke, scheint aber mit 16MHz zu laufen im sequential Mode, da 
ich im Atmega-Datenblatt nichts über DualSerialMode gefunden habe wohl 
in SPI.
Aber der Datendurchsatz sieht in diesem Falle ja gar nicht so schlecht 
aus.

Dirk K. schrieb:
> Grade gesehen, du willst Byte für Byte schreiben/lesen und jedes
> mal mit Adresse ansprechen. Mit solch einem Setup und den
> Arduino-Libraries bin ich etwa auf 8 kByte/s gekommen. Vielleicht lässt
> sich da ein wenig durch direkte µC-Programmierung rausholen oder durch
> Gruppierung mit einem kleinen Puffer.

Ja, "direkte" µC-Programmierung nicht ganz, ich nutze eigentlich lieber 
C wie Assembler, in letzteres müsste ich mich auch erst wieder 
reinarbeiten.
Diese Gruppierung schwebte mir auch schon vor, ggf. im µC jeweils zwei 
Pages vorhalten, die könnte man dann schonmal in akzeptabler 
Geschwindigkeit lesen, allerdings müssen diese dann auch noch im 
Hintergrund mit den FIFO-Grenzen konsistet gehalten werden.

Wenn ich die 456kbyte/s seq. bei 16MHz mal auf 18,432MHz byte umrechne
komme ich auf etwas um die 105kB/s (456/16/18,432/5)?

Frank K. schrieb:
> Ich denke, Dein Systemdesign ist ziemlich auf Kante genäht.
>
> Ich empfehle Dir einen dsPIC33EP512GP502 oder einen PIC32MX250F128B,
> beides auch 28 Pinner, mit 16 Bit/70 MHz/48k bzw 32Bit/50MHz/32k RAM
> intern. Der große Vorteil ist, dass diese Prozessoren DMA-Controller
> eingebaut haben, die Daten von/zu einer Peripherieeinheit ohne
> Prozessorhilfe quasi im Hintergrund übertragen können. Das und der große
> interne Speicher vereinfachen vieles. Außerdem hast Du eine erheblich
> höhere Prozessorleistung, und das alles für nur 2€ mehr.

Ich habe sowohl einen 32MX150F128B-ISP als auch einen 32MX210F016B-ISP 
hier liegen, kam mir aber, außer in Anbetracht des großen Speichers, 
etwas wie mit Kanonen auf Spatzen schießen vor und zudem konnte ich mich 
mit dem MPLAB noch nicht so ganz anfreunden ;-)

Gruß Dominik

von Dirk K. (dekoepi)


Lesenswert?

Vorsicht mit den MHz/SPI auf dem Arduino-Krempel. Der ATmega328 wird mit 
16MHz extern auf Trab gebracht. SPI ist damit erstmal 4 MHz maximal 
(F_CLK/4 laut Datenblatt), in einem zweiten Register kann man aber SPIx2 
setzen und somit auf 8 MHz "aufrüsten". Da deine Rechnung aber relativ 
ist, kommt das mit dem Verhältnis hin ;) Außer natürlich - wo kommt die 
5 her? ich schreibe ganz normal seriell in ein SPI-Modul. Ist eines 
voll, schalte ich einfach auf das nächste. Oder willst du einen 
5-Byte-Puffer nutzen?

: Bearbeitet durch User
von Dominik V. (Firma: TBV) (d190979v)


Lesenswert?

Hallo Dirk,

Dirk K. schrieb:
> Vorsicht mit den MHz/SPI auf dem Arduino-Krempel.

Nein, einen Ardudingsbums habe ich nicht ;-)

Dirk K. schrieb:
> er ATmega328 wird mit
> 16MHz extern auf Trab gebracht. SPI ist damit erstmal 4 MHz maximal
> (F_CLK/4 laut Datenblatt), in einem zweiten Register kann man aber SPIx2
> setzen und somit auf 8 MHz "aufrüsten". Da deine Rechnung aber relativ
> ist, kommt das mit dem Verhältnis hin ;)

Sowohl ATmega328 als auch ATiny2313 laufen mit Grundtonquarz auf 18,432 
MHz
stabil in den jetzt wieder vor mir stehenden Steckbrettern. Meine 
ursprüngliche Sorge galt eigentlich den Prozessortakten, die dem SPI zum 
Opfer fallen, bei dem ATmega scheinen dies in der Tat nur die 
Registerabfragen und Schreiben/Lesen des Datenregisters zu sein, beim 
ATTiny hatte ich Zweifel, jedoch scheint dort zwar der TIMER0 geopfert 
werden zu müssen, aber das Byte wandert dann ja wohl doch im Hintergrund 
(hardwaremäßig) über die Leitung.
Ja, jetzt habe ich auch den(deinen?) Quelltext mal in formatierter Form 
gesehen, also:
SPCR-> SPI on, Master, F_CPU/4
SPSR-> 2x
Ok, dann läuft der SPI tatsächlich mit 8MHz, befüllt wird über 
for-schelife
mit eigenen Funktionsaufrufen write...
Der Bus selber sollte in der Konfiguration ca. 1000k transportieren 
können, limitierend ist logischerweise das Hauptprogramm.

Meine Überschlagsrechnung, die sich auf die relative Datenmenge bezog, 
wirkt sich, da sie auf dem Prozessortakt aufsetzt, also wahrscheinlich 
(zwar nur bei diesem Programm) genau so aus, die /5 ist der Unterschied 
zwischen sequential und byte:
8 bit Daten (Mode 8 && Adresse 20 nur einmal, daher vernachlässigbar)
zu
40 bit Daten (mode 8  Adresse 24  daten 8).

Wie sieht denn bei dieser relativ hohen Anbindung von 8MHz die 
Infrastruktur aus? Lang dürfen die Leitungen dann doch sicher nicht mehr
sein - oder?

Gruß Dominik

von Dirk K. (dekoepi)


Lesenswert?

Meine Verbindungskabel habe ich aus Klingeldraht selber gebastelt. An 
der Platine des µC kommen dann 5-7cm Anschlussdraht. Die Speicherbank 
selber führt die Leitungen dann via Silberdraht weiter, nochmal etwa 
7cm.

Trotz der 8 MHz, einiger böser Lötstellen und ähnlichem aber problemlos, 
was die Signalqualität anbelangt.

Die 1mByte/s hatte ich auch gehofft, aber es scheint so, dass die 8 MHz 
nochmal halbiert werden müssen - eine "Vollwelle" ist ja ein Takt an, 
einen aus, sozusagen. (Bin kein Elektroniker, daher bitte die schlechte 
Erklärung (aus meinen laienhaften (un)Verständnis) nachsehen.)

: Bearbeitet durch User
von Dominik V. (Firma: TBV) (d190979v)


Angehängte Dateien:

Lesenswert?

Hallo Dirk,
das lässt hoffen, dass ich ähnliche Resultate erziele. Der 
Datendurchsatz wird wohl ausreichen, habe den USART im Moment bei 16k, 
Protokoll und Blockgröße werde ich aber noch optimieren.
Eine Frage habe ich noch, hast Du beim Ansprechen im Byte-Modus dem 
Speichers ein Dummy-Byte zum Daten abholen geschickt oder den nächsten 
Instruction-Befehl? (macht ja bei dem Speicher schon 20% 
Performance-Unterschied aus) Geht das?

Gruß Dominik

von Dominik V. (Firma: TBV) (d190979v)


Angehängte Dateien:

Lesenswert?

Hallo Dirk,
Warum ich gefragt habe...
Nachtrag:

Siehe Anhang MAP004 - 7 bytes
Siehe Anhang MAP007 - 8 bytes

Sollte also die nächste Instruction parallel zum Datenabruf möglich 
sein, funktioniert mein Systemdesign mit dem 512er Speicher im 
BYTE-Zugriff, ansonsten muss ich generell auf PAGE oder SEQUENTIAL 
umsteigen.
In den Beiden OSZI-Abdrücken sieht man es im oberen Signalverlauf des 
MOSI (unteres Signal UART bei 17k), bei 7 byte ist noch Platz, bei 8 
byte ist es sehr auf "Kante genäht".
Der SPI arbeitet hier schon mit 2 er Teiler = 9,216 MHz.

Gruß Dominik

P.S.: Doppel-Anhang-Post, sorry hat die Änderung im vorherigen Beitrag 
wohl doch übernommen.

: Bearbeitet durch User
von Dirk K. (dekoepi)


Lesenswert?

Hallo  Dominik,

dem Speicher ist es egal, was du ihm als Dummy-Byte im READ-Modus 
schickst. Nur wird er den Befehl nicht als solchen erkennen dann. Zum 
Befehl absetzen musst du immer CS auf HIGH setzen, CS wieder LOW setzen, 
Befehl und Datum schicken, wieder das HIGH/LOW-Spiel ...

Also das weitere komprimieren der Kommunikation klappt so leider nicht.

Pagemode mit einem 32-Byte-Puffer klingt doch ok. Oder eben Sequential 
Mode, wenn du nicht jedes Datum sofort wieder lesen musst, sondern 
einfach erstmal nur Daten wegspeichern willst. Das spart dann maximal 
Overhead.

: Bearbeitet durch User
von Dominik V. (Firma: TBV) (d190979v)


Lesenswert?

Hallo Dirk,

Dirk K. schrieb:
> dem Speicher ist es egal, was du ihm als Dummy-Byte im READ-Modus
> schickst. Nur wird er den Befehl nicht als solchen erkennen dann. Zum
> Befehl absetzen musst du immer CS auf HIGH setzen, CS wieder LOW setzen,
> Befehl und Datum schicken, wieder das HIGH/LOW-Spiel ...

stimmt, habe es gerade im Sequenzdiagramm gesehen. Ansonsten war die 
Idee ja nicht schlecht.

> Pagemode mit einem 32-Byte-Puffer klingt doch ok. Oder eben Sequential
> Mode, wenn du nicht jedes Datum sofort wieder lesen musst, sondern
> einfach erstmal nur Daten wegspeichern willst. Das spart dann maximal
> Overhead.

Denke so werde ich es machen, dann ist es ja prinzipiell auch total egal 
ob ich den 512k oder 1M Speicher nehme, die Zeiger haben in beiden 
fällen immer die gleiche Größe. Hast Du den µC mittels SPI programmiert? 
Macht es Probleme den Speicher am Bus zu lassen? Denke mal der funkt 
dann alle x byte mal dazwischen, also CS mit Pull-Up und Jumper 
vorsehen, oder?

Gruß Dominik

von Dirk K. (dekoepi)


Lesenswert?

Das Board habe ich per USB programmiert, ist ein schön fertig 
aufgebauter Arduino Nano (oder auch Pro Mini). Im Wesentlichen ist das 
USART mit Rx/Tx via USB-Seriell-Wandler.
Die SPI-Peripherie kannst du dran lassen, auch wenn du den ATmega 
darüber programmierst. Die Chips funken nichts, wenn sie nicht gefragt 
werden; denen ist auch alles auf den Leitungen egal, sofern du nicht mit 
dem CS-Finger auf sie zeigst. :)

: Bearbeitet durch User
von Dominik (Gast)


Lesenswert?

Hallo Dirk,

Dirk K. schrieb:
> Das Board habe ich per USB programmiert, ist ein schön fertig
> aufgebauter Arduino Nano (oder auch Pro Mini). Im Wesentlichen ist das
> USART mit Rx/Tx via USB-Seriell-Wandler.
> Die SPI-Peripherie kannst du dran lassen, auch wenn du den ATmega
> darüber programmierst. Die Chips funken nichts, wenn sie nicht gefragt
> werden; denen ist auch alles auf den Leitungen egal, sofern du nicht mit
> dem CS-Finger auf sie zeigst. :)

stimmt ja, die SS/CS Leitung ist ja gar nicht mit dem programmieradapter 
verbunden, also mache ich dort einen pull-up dran, spart sogar eine 
Zeile quelltext ?

Gruß dominik

von Dominik V. (Firma: TBV) (d190979v)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
Hallo Dirk,

die Speicherchips sind gestern schon von Mikrochip-Direkt aus Thailand 
eingetroffen, super verpackt und super schnell. Preislich auch dtl. 
unter den Resellern (wobei die meisten diese Chips auch gar nicht im 
Sortiment haben).
Ich habe dann gestern mal einen ersten Versuch im Byte-Mode gemacht, Der 
ATMGEA schreibt die USART-Daten direkt per SPI in den Chip, nachdem die 
128k abgespeichet sind, liefert er diese auch direkt wieder per USART 
aus (Quick n´dirty):

void LCV_PushByte(uint8_t data)
{
  LCV_PORT &= ~(1<<LCV_CS); //SS/CS auf low
  SPI_MasterTransmit(LCV_WRITE);   //Write Instruction
  SPI_MasterTransmit(lcvWritePointer>>16); //24bit-Adresse 23LCV1024
  SPI_MasterTransmit(lcvWritePointer>>8);  //16bit-Adresse 23LCV512
  SPI_MasterTransmit(lcvWritePointer);
  SPI_MasterTransmit(data);
  LCV_PORT |= (1<<LCV_CS); //SS/CS auf high
  lcvWritePointer++;
  if(lcvWritePointer==131072UL)
    lcvWritePointer=0;
  lcvUsed+=1;
}

do //Hauptprogramm
{
  while(lcvUsed<131072L)
  {
    while( !(UCSR0A & (1<<RXC0)) );
    LCV_PushByte(UDR0);
  }
  while(lcvUsed>0)
  {
    while(!(UCSR0A & (1<<UDRE0)));
    UDR0=LCV_PullByte();
  }
} while(1);

(Die Pull-Funktion ist der Push-Funktion weitestgehend ähnlich.)

Bei dieser Vorgehnsweise limitiert im Moment der USART den 
Datendurchsatz
auf 23k (Übertragen: 128blöcke 262144byte Zeit=11.375s 
Byte/s=23045.626373626375). Der SPI-Bus läuft bei 9.216 MHZ auf einem 
Breadboard. LOL. Die Oszi-Abdrucke zeigen oben MOSI und unten MISO. Es 
ist also bei so einer Vorgehensweise noch reichlich Platz auf dem Bus. 
Allerdings nicht genug um gleichzeitig zu lesen, selbst wenn das 
restliche Programm 0 Takte verbrauchen würde. Mit dem 512er würde es so 
gerade gehen. Aber das war ja nach den Berechnungen im Vorfeld schon 
klar. Ansonsten gefällt mir der 23LC*XXXX schonmal echt spitze. 
Insbesondere da er nur die gleichen Pins + CS belegt, die ohnehin für 
den ISP reserviert waren.

Frage an die C-Profis: Die If-Abfrage in der PUSH-Funktion gefällt mir 
pers. garnicht, allerdings bekomme ich immer nur Datenmüll wenn ich die 
bedingte Zuweisung =()?: mit 32 bit Variablen nutze, weiß einer woran 
das liegen kann, war bis jetzt eigentlich immer ein Problem.

Gruß Dominik

: Bearbeitet durch User
von Dominik V. (Firma: TBV) (d190979v)


Angehängte Dateien:

Lesenswert?

Hallo Dirk,
kleine Ergänzung, so sieht es auf dem Bus aus wenn man in den 
SEQENTIAL-MODE umschaltet (allerdings bei gleichem Hauptprogramm). So 
jetzt muss ich das
ganze noch Interrupt-Save machen ;-)

Danke für die Hilfestellungen.

Gruß Dominik

von Frank K. (fchk)


Lesenswert?

Dominik V. schrieb:

> Frage an die C-Profis: Die If-Abfrage in der PUSH-Funktion gefällt mir
> pers. garnicht, allerdings bekomme ich immer nur Datenmüll wenn ich die
> bedingte Zuweisung =()?: mit 32 bit Variablen nutze, weiß einer woran
> das liegen kann, war bis jetzt eigentlich immer ein Problem.

Mach doch einfach

lcvWritePointer&=131071UL;

Damit hast Du eine konstante Laufzeit.

von Dirk K. (dekoepi)


Lesenswert?

Sequential sieht doch super aus! :)

Schön, dass es funktioniert :)

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.