Forum: Mikrocontroller und Digitale Elektronik SRAM auslesen zu langsam.


von Hack K. (hackerfleisch)


Lesenswert?

Hi zusammen,

Hardware:
µC = ATMega32 16MHz
4 x SRAM von ST (M68AW031A) 256Kbit (32K x8)

Verdrahtung vom SRAM zum µC:
PORTB(PB0 - PB7) = Adresse0 - Adresse7 (SRAM)
PORTA(PA1 - PA7) = Adresse8 - Adresse14 (SRAM)
PORTC(PC0 - PC7) = Daten DQ0 - DQ7 (SRAM)


ich habe ein Problem mit meinem C code und dem auslesen von SRAM 
Bausteine.
Ich befülle diese (4st. à 32Kx8Bit -> 1MB) davor via RS232 mit Daten. 
Diese Daten sind 16Bit Werte. Also lege ich jeweils in die erste 8Bit 
Zeile das HighNibble und in die zweite Zeile das LowNibble des 16Bit 
Wertes.


Später lese ich mit einem Interrupt vom Timer2 (TIMER2_COMP_vect) diese 
Daten wieder aus und baue wieder eine 16Bit Adresse zusammen und 
übergebe diese dann dem OCR1A Register vom Timer1. Dieser macht dann 
eine PulsPausenModulation, welche über Tiefpässe geht um eine variable 
Ausgangsspannung zu bekommen.

Mein Problem ist die Stelle am Timer2 (wo die 2x8Bit Werte aus dem SRAM 
gelsen werden und dem OCR1A übergeben wird). Der Timer2 taktet mit 
einstellbarer frequenz um daraus eine Samplerate für den OCR1A hin zu 
bekommen. Wenn ich den Timer2 mit z.B. 250Samples/s laufen lasse (also 
250 mal lößt der interrupt aus um den SRAM aus zu lesen) passt noch 
alles.

Wenn ich jedoch die Samplerate erhöhe (auf 5000Hz -> 5000Samples/s), 
werden einige Interrups "verschluckt". Wenn ich zum Testen einen PortPin 
toggeln lasse um zu sehen wie lange der µC braucht, sehe ich, dass es 
~206 - 210µs sind. Es dürften jedoch max. 200µs sein, da die Periode von 
5000Hz = 200µs sind.

Mein kongrete Frage hierzu ist:
Kann ich den code zum auslesen des SRAM noch etwas optimieren, damit ich 
Sampleraten von 5000 hin bekomme? In der ISR steht viel zu viel drin, 
damit diese schnell abgearbeitet werden kann, normalerweise sind bei den 
anderen ISrs immer ~5 - 15 Zeilen drin, in dieser jedoch einige mehr. 
Ich denke da ist der Hund begraben...


Hier mal ein snippet vom Auslesen des SRAM (
1
ReadSRAM(long Address)
) welche von der Funktion (
1
PlayStartCurveFromRAM(void)
) aufgerufen wird. Diese Funktion wird wiederum von der ISR (
1
ISR(TIMER2_COMP_vect)
) aufgerufen.


Nachtrag:
Die Divider in der TIMER2_COMP_vect ISR sind dafür da, um einen software 
vorteiler zu realisieren. der Timer2 taktet mit mit einem Prescaler von 
128 = 125000 Hz. Je nach Divider1 & Divider2 sind sampleraten (in der 
theorie von 125000 - 4 Hz machbar). Jedoch in der ISR aber code drin 
steht wird diese langsamer ODEr es werden welche "verschluckt" (Mit dem 
Oszi nachgemessen).


Schon mal vielen Dank im voraus!

Gruß
Thomas D.

1
ISR(TIMER2_COMP_vect)
2
{
3
  /*This Timer2 compare vector service routine generate the samplerate for
4
  the start curve. See the Table below (timer2_init()) for more informations.
5
  Divider1 and Divider2 values set the samplerate.
6
  Example: Samplerate = 5000 samples/sec.
7
    -> Divider1 = 24 (25 steps [0 - 24]).
8
    -> Divider2 = 0
9
  Divider1 & Divider2 are each 8Bit counter. The count clock is
10
  F_CPU/Prescale -> 16MHz/128 = 125KHz.
11
  Divider2 is a counter in a counter (Divider2 will increment when Divider1 is overflow).
12
  */
13
  
14
  if (Divider1 < Divider1_limit) //Current count value (Divider1) < count limit (Divider1_limit).
15
  {
16
    Divider1++; //Increment Divider1 register.
17
  }
18
  else //If Divider1 >= Divider1_limit.
19
  {
20
    Divider1 = 0; //Set Divider1 to default count value (re-start).
21
    if (Divider2 < Divider2_limit) //Current count value (Divider2) < count limit (Divider2_limit).
22
    {
23
      Divider2++; //Increment Divider2 register.
24
    } 
25
    else //If Divider2 >= Divider2_limit.
26
    {
27
       PlayStartCurveFromRAM();
28
       Divider2 = 0; //Set Divider2 to default count value (re-start).
29
    }
30
  }
31
}

1
void PlayStartCurveFromRAM(void)
2
{
3
  if(fSRAM_Address_Pointer < fSRAM_Address) 
4
  {
5
    TempH = ReadSRAM(fSRAM_Address_Pointer);
6
    fSRAM_Address_Pointer++;
7
    TempL = ReadSRAM(fSRAM_Address_Pointer);
8
    fSRAM_Address_Pointer++;
9
    OCR1A = (((uint16_t)TempH << 8) | TempL);
10
  }
11
  else
12
  {  
13
    TCCR2 = 0b00001000;
14
    OCR1A = (((uint16_t)TempH << 8) | TempL);
15
    fSRAM_Address_Pointer = 0;
16
  }
17
}
1
uint8_t ReadSRAM(long Address)
2
{
3
  /*
4
  Truth table of Multiplexer.
5
  IC 4051 (MUX):
6
  µC Pin:       (PD6)   (PD2) |  (Out)   (Out)   (Out)   (Out)
7
  MUX Pin:    11    10   |  13    14    15    12
8
          _____________|____________________________
9
          A    B   |  X0    X1    X2    X3
10
          L    L   |  L    H    H    H
11
          H    L   |  H    L    H    H
12
          L    H   |  H    H    L    H
13
          H    H   |  H    H    H    L
14
  
15
  PD6 = L & PD2 = L -> 1.(SRAM IC14) -> Address: 0x00000 - 0x07FFF.
16
  PD6 = H & PD2 = L -> 2.(SRAM IC12) -> Address: 0x08000 - 0x0FFFF.
17
  PD6 = L & PD2 = H -> 2.(SRAM IC11) -> Address: 0x10000 - 0x17FFF.
18
  PD6 = H & PD2 = H -> 4.(SRAM IC13) -> Address: 0x18000 - 0x1FFFF.
19
  
20
  Maximum allowed Address 0x7FFF = 2^15 = A0 - A14 (SRAM Address).
21
  */
22
23
  DDRC = 0x00; //PORTC as Input (read Data from DQ0 - DQ7).
24
  PORTD |= (1 << PD3); //Set PD3 to high, to disable the Write Enable Pin in SRAM (LOW active).
25
   uint8_t Data = 0;
26
27
28
29
30
31
  if (Address >= 0x00000 && Address <= 0x07FFF) //Enable SRAM IC 14.
32
  {
33
    PORTD &= ~(1 << PD6); //Set MUX Channel A to Low (see truth table above for details).
34
    PORTD &= ~(1 << PD2); //Set MUX Channel B to Low (see truth table above for details).
35
  }    
36
  if (Address >= 0x08000 && Address <= 0x0FFFF) //Enable SRAM IC 12.
37
  {
38
    PORTD |= (1 << PD6); //Set MUX Channel A to high (see truth table above for details).
39
    PORTD &= ~(1 << PD2); //Set MUX Channel B to Low (see truth table above for details).
40
41
    //Subtract the maximum available capacity of the 1st. SRAM module to get the right value.
42
    Address -= 0x08000;
43
  }
44
  if (Address >= 0x10000 && Address <= 0x17FFF) //Enable SRAM IC 11.
45
  {
46
    PORTD &= ~(1 << PD6); //Set MUX Channel A to low (see truth table above for details).
47
    PORTD |= (1 << PD2); //Set MUX Channel B to high (see truth table above for details).
48
    
49
    //Subtract the maximum available capacity of the 1st. & 2nd. SRAM module to get the right value.
50
    Address -= 0x10000;
51
  }
52
  if (Address >= 0x18000 && Address <= 0x1FFFF) //Enable SRAM IC 13.
53
  {
54
    PORTD |= (1 << PD6); //Set MUX Channel A to high (see truth table above for details).
55
    PORTD |= (1 << PD2); //Set MUX Channel B to high (see truth table above for details).
56
    
57
    //Subtract the maximum available capacity of the 1st. & 2nd. & 3rd. SRAM module to get the right value.
58
    Address -= 0x18000;
59
  }
60
61
            //   AddressLowNibble = Address; //Read out the low nibble and set it in Address (lower 8 from 15 Bits).
62
            //   Address = (Address / 256); //Shift Address 8 bits to right to get the higher nibble from Address (last 7 Bits [9 - 15]).
63
            //   AddressHighNibble = Address; //Save the last 7 Bits.
64
            //   AddressHighNibble = (AddressHighNibble*2); //Shift all 7 Bits to left, from PA0 - PA6 to PA1 - PA7 (PA0 is ADC Input!).
65
  
66
  PORTB = Address; //Read out the low nibble and set it as Address for SRAM to PORTB (A0 - A7).
67
  PORTA = (Address >> 7); //Read out the high nibble and set it as Address for SRAM to PORTA (A8 - A14).
68
69
70
  PORTD |= (1 << PD3); //Set PD3 to high, to disable the Write Enable Pin in SRAM (LOW active).
71
  _delay_us(0.05); //Time to set Data into PORTC from SRAM.
72
  Data = PINC; //Get Data from SRAM, saved in var Data.
73
74
  DDRC = 0xFF; //Set PORTC back to Output.
75
  PORTB = 0; //Clear Low Nibble Address.
76
  PORTA = 0; //Clear High Nibble Address.
77
  PORTD &= ~(1 << PD6); //Set PD6 (MUX A) back to default (low).
78
  PORTD &= ~(1 << PD2); //Set PD2 (MUX B) back to default (low).
79
80
  return Data;  
81
}

von Georg G. (df2au)


Lesenswert?

sieh dir mal den Code von _delay_us() an. Ich würde hier einfach nur 
einen nop spendieren (wenn dein SRAM zu langsam ist).

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Nimmste nen AVR mit Hardware Speicherinterface und der saugt dir das in 
paar Takten ausm SRAM.

von Joerg W. (joergwolfram)


Lesenswert?

Schon Deine Adresskodierung über PD2 und PD6 ist viel zu umständlich. 
Schneller sollte es so gehen:
1
if((Address & 0x8000) == 0)
2
{
3
    PORTD &= ~(1 << PD6); //Set MUX Channel A to Low
4
}
5
else
6
{
7
    PORTD |= (1 << PD6); //Set MUX Channel A to high
8
}
9
10
11
if((Address & 0x10000) == 0)
12
{
13
    PORTD &= ~(1 << PD2); //Set MUX Channel B to Low
14
}
15
else
16
{
17
    PORTD |= (1 << PD2); //Set MUX Channel B to high
18
}

Jörg

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

deine sogenannte Adressverwaltung ist viel zu kompliziert gedacht. RAM 
addressiert man linear, bei 4 St. 32k-Chips sind das 15 Bit direkt an 
die Chips und 2 Bit an einen 2 zu 4 Dekoder - da gibt es schlichtweg 
nichts zu rechnen!

Einfach mit 17 Bit zählen und den Zählerstand ausgeben, fertig ist die 
Adressierung. Wenn dann die Zeit nicht reicht, dann gehts eben wirklich 
nicht.

Gruss Reinhard

von Falk B. (falk)


Lesenswert?

@  Martin Wende (Firma: fritzler-avr.de) (fritzler)

>Nimmste nen AVR mit Hardware Speicherinterface und der saugt dir das in
>paar Takten ausm SRAM.

Richtig. Und wenn es mehr als 64kB sein sollen, macht man halt old 
school ne Bankumschaltung.

von Hack K. (hackerfleisch)


Lesenswert?

Hi!

@Georg G.
Verstehe ich nicht ganz was Du damit sagen willst. der SRAM benötigt 
min. 70ns Zeit um sich einzustellen (Laut datenblatt). Da das setzen von 
PD3 schon etwas dauert, reichen hier 50ns. funtioniert auch wunderbar...

@Joerg Wolfram
Danke für den Tipp, werd das mal so probieren, jedoch benötigt diese 
adressierung am wenigsten Zeit von der Funktion. :(
Werde diese aber einbauen.

@Reinhard Kern
ein µC mit Speicherinterface hätte ich auch gerne genommen, diese HW war 
aber schon fertig gelayoutet. Ich muss hier nur den ATMega statt ein 
C-control µC ersetzen da der C-Control viel zu langsam war.

Zwecks der Adressierung und der 17Bit. Das mache ich eigentlich, nur in 
zwei steps.
Die 4 SRAMs sind parallel geschaltet, über ein MUX (2 zu 4) wähle ich 
dann den richtigen IC...

von Reinhard Kern (Gast)


Lesenswert?

Thomas D. schrieb:
> Die 4 SRAMs sind parallel geschaltet, über ein MUX (2 zu 4) wähle ich
> dann den richtigen IC...

Und wozu um alles in der Welt brauchst du dazu Subtraktionen??

Gruss Reinhard

von am falschen Rechner (Gast)


Lesenswert?

Thomas D. schrieb:
> reichen hier 50ns

Sieh dir bitte mal an, wie lange ein _delay_us(0.05) in der Realität 
dauert und welche Menge Code dafür eingebunden wird. Die delay Funktion 
rechnet intern mit double Gleitkomma! Mit einem oder zwei inline nop 
bist du besser bedient.

von (prx) A. K. (prx)


Lesenswert?

Thomas D. schrieb:
> Address -= 0x08000;

Überflüssig, da im weiteren Verlauf ohnehin nur die unteren 15 Bits 
genutzt werden.

> PORTA(PA1 - PA7) = Adresse8 - Adresse14 (SRAM)
> PORTA = (Address >> 7);

Ungünstig. PA0..6 wär einfacher, da >>8 billiger ist als >>7.

>   DDRC = 0xFF; //Set PORTC back to Output.
>   PORTB = 0; //Clear Low Nibble Address.
>   PORTA = 0; //Clear High Nibble Address.
>   PORTD &= ~(1 << PD6); //Set PD6 (MUX A) back to default (low).
>   PORTD &= ~(1 << PD2); //Set PD2 (MUX B) back to default (low).

Was bringt dir dieser ganze Zauber? Der Kram wird das nächste Mal 
ohnehin komplett neu gesetzt und bis dahin interessiert es niemanden.

> über ein MUX (2 zu 4) wähle ich dann den richtigen IC...

Das ist ein Decoder, kein Mux.

von Falk B. (falk)


Lesenswert?

@  am falschen Rechner (Gast)

>> reichen hier 50ns

>Sieh dir bitte mal an, wie lange ein _delay_us(0.05) in der Realität
>dauert und welche Menge Code dafür eingebunden wird.

Genau DAS solltes DU mal tun.

> Die delay Funktion
>rechnet intern mit double Gleitkomma!

Jain. Nur wird das vom Compiler zur Compilezeit gemacht, nicht zur 
Laufzeit. Wenn die Optimierung eigeschaltet ist ;-)

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29

>Mit einem oder zwei inline nop
>bist du besser bedient.

Kommt auf das Gleiche raus.

von (prx) A. K. (prx)


Lesenswert?

A. K. schrieb:
>> über ein MUX (2 zu 4) wähle ich dann den richtigen IC...
>
> Das ist ein Decoder, kein Mux.

PS: Das IC mag ein Muxer sein, dessen Verschaltung ist hier ein Decoder.

von (prx) A. K. (prx)


Lesenswert?

Kannst du mal die komplette Verschaltung vom RAM posten? Also nicht nur 
CE und WE, sondern auch OE. Und auch skizzieren, was mit OE im Code so 
alles passiert. Der Ablauf davon sieht nämlich etwas seltsam aus. Kommt 
nicht oft vor, dass man beim Lesen die Schreibleitung steuert (und evtl. 
beim Schreiben die Leseleitung?). Üblich wärs andersrum.

von Hack K. (hackerfleisch)


Lesenswert?

Ja gibt es, diese steht in der WriteSRAM Funktion. Diese  ist hier aber 
nicht gelistet. Da über diese Funktion daten auf das SRAM geladen 
werden, ist dies nicht zeitkritisch.

Zwecks MUX bin ich davon ausgegangen das jeder weis was ich mein...

@Joerg Wolfram
Hab Dein Vorschlag eingebaut, funktioniert damit ja auch. Nur ohne Erolg 
auf die performance.


Es muss doch möglich sein in 200µs zwei mal einen 8Bit wert am PORTC zu 
lesen (davor die Adresse einstellen) und diese dann über casting ins 
OCR1A Register zu schieben, hätte nicht gedacht das genau hier von den 
insg. 1500 Zeilen code Probleme auftreten. :(

Gruß
Thomas D.

von (prx) A. K. (prx)


Lesenswert?

Thomas D. schrieb:
> Ja gibt es, diese steht in der WriteSRAM Funktion. Diese  ist hier aber
> nicht gelistet. Da über diese Funktion daten auf das SRAM geladen
> werden, ist dies nicht zeitkritisch.

Ist in diesem Aspekt nicht der Punkt. Ich habe den konkreten Verdacht, 
das dein Datenbus die meiste Zeit auf Krawall gebürstet ist, also 
Ausgang gegen Ausgang steht. Wenn OE permanent aktiv ist, dann sind die 
Datenleitungen vom RAM aktiv sobald CE=0,WE=1. Also die von Bank 0 
meistens. Dein Port C ist es aber auch...

Üblich wärs eigentlich, in der Leseroutine für die Dauer vom Zugriff OE 
zu aktivieren und in der Schreibroutine analog WE.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Thomas D. schrieb:
> Es muss doch möglich sein in 200µs zwei mal einen 8Bit wert am PORTC zu
> lesen (davor die Adresse einstellen) und diese dann über casting ins
> OCR1A Register zu schieben, hätte nicht gedacht das genau hier von den
> insg. 1500 Zeilen code Probleme auftreten. :(
Dann sieh dir doch einfach mal den Assemblercode an....

BTW: hast du verstanden, was da im 
Beitrag "Re: SRAM auslesen zu langsam." gemeint ist?

Ein Tipp: Zeichen mal deine Adressleitungen A15 und A16 auf. Und dann 
daneben die Eingänge vom Multiplexer.
Warum verwendet man einen Analogmultiplexer zur Ansteuerung eines 
digitalen Bausteins?

>>>> SRAM auslesen zu langsam
1
PORTD |= (1 << PD3); //Set PD3 to high, to disable the Write Enable Pin in SRAM (LOW active).
2
:
3
:
4
:
5
PORTD |= (1 << PD3); //Set PD3 to high, to disable the Write Enable Pin in SRAM (LOW active).
Warum bastelst du in der Leseroutine laufend am WE# rum?
1
  PORTD &= ~(1 << PD6); //Set PD6 (MUX A) back to default (low).
2
  PORTD &= ~(1 << PD2); //Set PD2 (MUX B) back to default (low).
Ist nicht jeder andere Wert genauso gut wie dieser "Defaultwert"?

Du jammerst, dass das Lesen zu lange dauert und dir die Zeit nicht 
reicht, verplemperst aber jede Menge Zeit mit unnötigen Aktionen...

von (prx) A. K. (prx)


Lesenswert?

Lothar Miller schrieb:
> Warum verwendet man einen Analogmultiplexer zur Ansteuerung eines
> digitalen Bausteins?

Ist zwar eine kuriose Methode, aber nicht wirklich ein Problem.

von Karl H. (kbuchegg)


Lesenswert?

Und wenn du schon mit kompletten Adressen rummachst

> uint8_t ReadSRAM(long Address)

Adressen können nicht negativ sein.
Also wäre das sinnvollerweise ein unsigned long.

Dann kommen jede Menge
  if (Address >= 0x00000 && Address <= 0x07FFF) //Enable SRAM IC 14.
und Subtraktionen und weiß der Kuckuck was noch.

Zerleg dir die 32 Bit Adresse gleich mal in die 2 Bits, die du zur 
Selektion brauchst und die restlichen 15 Bit. Die 15 Bits interessieren 
dich nicht weiter, die gibst du an den Port aus.
Und die 2 Bits legst du an DB6 bzw. DB2.
Es gibt da keinen Grund für Vergleichsorigien bzw. Subtraktionen. Und 
schon gar nicht gibt es da einen Grund dafür, deinen µC dafür in 32 Bit 
Arithmetik hineinzutreiben.

Es heißt zwar immer 'vorzeitige Optimierung sei die Wurzel allen übels'. 
Aber auf der anderen Seite muss man seinen µC auch nicht sinnloserweise 
in Beschäftigungstherapie treiben, in dem man ihm naheliegende 
Vereinfachungen vorenthält. Und wenn du ihn mutwillig in 32 Bit 
Arithmetik hineintreibst, dann darfst du dich über fehlenden Speed nicht 
wundern.

von Karl H. (kbuchegg)


Lesenswert?

Und für die Zukunft

1
  if (Address >= 0x00000 && Address <= 0x07FFF) //Enable SRAM IC 14.
2
  {
3
    ...
4
  }    
5
  if (Address >= 0x08000 && Address <= 0x0FFFF) //Enable SRAM IC 12.
6
  {
7
    ...

Eine Adresse kann nicht negativ sein. Wenn sie es jemals ist, dann 
deswegen, weil du für Address einen long genommen hast, der eigentlich 
ein unsigned long sein sollte. Und ein unsigned long kann per Definition 
nicht kleiner als 0 sein.
d.h die erste Abfrage nach >= 0 ist schon mal sinnlos. Den für einen 
unsigned long ist das trivialerweise IMMER erfüllt.

weiters: wenn dein erstes if korrekterweise erkannt hat, dass sich die 
Adresse im Bereich 0 bis 0x07FFF bewegt, dann KANN trivialerweise der 
nächste if (und alle weiteren) nicht mehr TRUE ergeben! d.h diese 
weiteren Tests sind sinnlose weitere Tests, die nur Zeit verbrauchen und 
sonst nichts. Und genau aus dem Grund wurde ein 'else' erfunden, um 
auszudrücken: Nur dann, wenn dieser Test nicht TRUE ergeben hat:
1
  if (Address <= 0x07FFF) //Enable SRAM IC 14.
2
  {
3
    ...
4
  }    
5
  else if (Address >= 0x08000 && Address <= 0x0FFFF) //Enable SRAM IC 12.
6
  {
7
    ...

(Sobald das erste if den Adressbereich erkannt hat, werden die anderen 
Adresstests gar nicht mehr gemacht.

Wenn aber das erste if den Adressbereich nicht erkannt hat, dann ist 
auch klar, dass sich die Adresse NICHT im Bereich 0 bis 0x07FFF bewegt. 
Daraus folgt aber auch, dass du nicht extra testen musst, ob die Adresse 
auch wirklich >= 0x08000 ist. Denn die MUSS größer/gleich sein. Wenn sie 
es nicht wäre, dann hätte der erste if das bereits erkannt und 
behandelt. D.h. du hast da einen Vergleich, der trivialerweise erfüllt 
sein MUSS! Andernfalls wäre das Programm überhaupt nie an diese Abfrage 
gekommen!
1
  if (Address <= 0x07FFF) //Enable SRAM IC 14.
2
  {
3
    ...
4
  }    
5
  else if (Address <= 0x0FFFF) //Enable SRAM IC 12.
6
  {
7
    ...

Bei einer Reihe von Bereichsprüfungen, bei denen die Bereiche nahtlos 
aneinander anschliessen, ist die Prüfung auf die Untergrenze eine 
sinnlose Operation. Denn durch die Anordnung der if bzw. else if ist 
automatisch sicher gestellt, dass die Untergrenze bereits von den 
vorhergehenden if bzw. else if korrekt erkannt wurde. Das muss man nicht 
extra testen und kostet nur Zeit, wenn der Compiler das nicht erkennt 
und wegoptimiert.

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Lothar Miller schrieb:
>> Warum verwendet man einen Analogmultiplexer zur Ansteuerung eines
>> digitalen Bausteins?
>
> Ist zwar eine kuriose Methode, aber nicht wirklich ein Problem.

Doch schon.
Man braucht zusätzliche Pullups, damit die nicht selektierten Pins nicht 
in der Gegend rumfloaten.


Peter

von Falk B. (falk)


Lesenswert?

@Peter Dannegger (peda)


>Man braucht zusätzliche Pullups, damit die nicht selektierten Pins nicht
>in der Gegend rumfloaten.

Vor allem, wozu wurden ICs wie der 74HC138 erfunden? Damit wird die 
ganze sinnlose Adressprüferei zu einer trivialen und schnellen 
Bitkopiererei.

1
uint8_t ReadSRAM(long Address)
2
{
3
   uint8_t Data;
4
   
5
   PORTB = Address & 0xFF;
6
   PORTA = (Address >> 8) & 0xFF;
7
   if (Address & 0x10000) PORTD |= (1<<PD6); else PORTD &= ~(1<<PD6);
8
   if (Address & 0x20000) PORTD |= (1<<PD2); else PORTD &= ~(1<<PD2);  
9
   PORTD &= ~(1<<PD0);    OE LOW, read data, 
10
   _delay_us(0.05); //Time to set Data into PORTC from SRAM.
11
   Data = PINC; //Get Data from SRAM, saved in var Data.
12
   PORTD |= (1<<PD0);    OE HIGH, read data finished
13
   return Data;  
14
}

Der ganze andere Mist ist vollkommen überflüssig. Dito eine 
Schreibroutine.

1
uint8_t ReadSRAM(long Address)
2
{
3
   uint8_t Data;
4
   DDRC= 0xFF;
5
   PORTC = Data;
6
7
   PORTB = Address & 0xFF;
8
   PORTA = (Address >> 8) & 0xFF;
9
   if (Address & 0x10000) PORTD |= (1<<PD6); else PORTD &= ~(1<<PD6);
10
   if (Address & 0x20000) PORTD |= (1<<PD2); else PORTD &= ~(1<<PD2);    
11
   PORTD &= ~(1<<PD1);    WE LOW, write data
12
   _delay_us(0.05); // write time for SRAM
13
   PORTD |= (1<<PD1);     WE HIGH, write data finished
14
   DDRC = 0x00;
15
}

Ist zwar immer noch deutlich langsamer als eine direkte Hardwarelösung, 
aber auch deutlich schneller als der akademische Murks.

Die Pins für WE und OE kenn ich jetzt nicht, hab einfach mal geraten.

von Georg G. (df2au)


Lesenswert?

Falk Brunner schrieb:
> Genau DAS solltes DU mal tun.

Und? Was ist dein Ergebnis? Stimmen die 50ns auch nur annähernd? 
Papier lesen ist etwas anderes als eine Sache auch mal auszuprobieren.

von Falk B. (falk)


Lesenswert?

1
#define F_CPU 1e6
2
#include <util/delay.h>
3
4
int main(void) {
5
6
    PORTD |= (1<<PD0);
7
  38:  90 9a         sbi  0x12, 0  ; 18
8
    can be achieved.
9
*/
10
void
11
_delay_loop_1(uint8_t __count)
12
{
13
  __asm__ volatile (
14
  3a:  81 e0         ldi  r24, 0x01  ; 1
15
  3c:  8a 95         dec  r24
16
  3e:  f1 f7         brne  .-4        ; 0x3c <main+0x4>
17
  _delay_us(0.05);
18
    PORTD &= ~(1<<PD0);
19
  40:  90 98         cbi  0x12, 0  ; 18
20
21
}

Drei Takte, wie zu erwarten. Klar, mit nop() kann man es taktgenau 
machen, war aber gar nicht die Kernaussage.

Beitrag "Re: SRAM auslesen zu langsam."

Einfach nur Blödsinn.

von Der (Gast)


Lesenswert?

Wahrscheinlich wird es schon funktionieren, wenn du nur die vorherigen 
Tipps beachtest.
Zusätzlich kannst du noch bedenken, dass ein Funktionsaufruf auch Zeit 
kostet. Je nach Optimierungsstufe ersetzt der Compiler das durch inline 
Funktionen. Auf der sicheren Seite bist du allerdings, wenn du die 
Geschichte direkt implementierst bzw. Makros verwendest.

Gruß

von Karl H. (kbuchegg)


Lesenswert?

> Wenn ich jedoch die Samplerate erhöhe (auf 5000Hz -> 5000Samples/s),
> werden einige Interrups "verschluckt". Wenn ich zum Testen einen
> PortPin toggeln lasse um zu sehen wie lange der µC braucht, sehe ich,
> dass es ~206 - 210µs sind. Es dürften jedoch max. 200µs sein, da
> die Periode von 5000Hz = 200µs sind.

Wobei allerdings:
Wenn man bei 16Mhz Taktfrequenz keine höhere ISR Frequent als 5000 
Aufrufe pro Sekunde hinkriegt, dann ist da mit Sicherheit noch was 
anderes faul. Das wären 3200 Takte von einem ISR Aufruf zum nächsten. So 
viel kann er gar nicht in der ISR verbraten haben. Noch nicht mal mit 
der ganzen 32-Bit Geschichte.

Es sei denn natürlich, der Optimizer war nicht angeschaltet und das 
_delay_us hat die komplette Floating Point Arithmetik nach sich gezogen. 
Aber dann gehören ihm sowieso die Ohren langgezogen.

von Reinhard Kern (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es gibt da keinen Grund für Vergleichsorigien bzw. Subtraktionen.

Das habe ich auch schon versucht zu erklären, er versteht da aber nur 
komplett Bahnhof. Das ist eben das Problem beim Copy&Paste, er weiss 
auch nicht annähernd was die Software eigentlich tut und warum. In dem 
Fall weiss ich es allerdings auch nicht, eigentlich gibt es nichts 
einfachers als einen Zählerstand auszugeben und die Daten einzulesen. 
Was sich der Programmierer bei ReadSRAM gedacht hat, ist mir ein 
komplettes Rätsel. Aber vielleicht verstehe ich den modernen 
Programmierstil nicht mehr.

Gruss Reinhard

von Ralph (Gast)


Lesenswert?

Werf das Layout weg und such dir einen geeigneten µC.
Vielleicht einen mit direkt genug internem Ram, oder zumindest ein HW 
interface für externe Ram Anbindung.

Wenn du die Zeit und Ärger rechnest die du in eine solche SW 
investierst, ist ein neues Layout allemal billiger.

von Karl H. (kbuchegg)


Lesenswert?

Wahrscheinlich reicht es schon, wenn er nicht mit Gewalt Zeit 
verplempert. Wenn die HW im Moment so ist, dann ist sie nun mal so.

von Hack K. (hackerfleisch)


Lesenswert?

An alle die nichts besseres zu tun haben wie nur die letzten zwei 
Einträge zu lesen und dann irgendwas schreiben wollen weil sie sonst 
nichts im leben zu sagen haben können mir gestohlen bleiben.
Das Problem ist mittlerweile gelöst, läuft alles wunderbar. 
Interessieren wird es hier wohl eh keinen, daher lass ich es mit der 
Erklärung.
Ist mir auch klar das einer der das ganze schon 10 jahre macht schneller 
ans ziel kommt, darum geht es hier aber nicht, eigeninitiative und Übung 
ist bei jedem gefragt der damit anfängt, positive kritik und 
Verbesserungen sind wichtig, dafur gibt es doch foren, oder?
Viele denken sie müssen aber gegen einen spielen um etwas zu beweisen.. 
ha da lach ich.

@kern
Werde erwachen... bitte!

Und warum immer so viel off topic herrscht verstehe ich nicht von wegen 
neue hw bauen etc. Wenn die leute mal alles gelesen hätten, wüssten die, 
das die hw fertig ist und nicht von mir ist... ich setze nur den mc auf 
die pcb. Daher bin ich an das pinning und an die randbeschaltung 
gezwungen.

An alle die etwas produktives geschriebenen haben, vielen dank! Hat mir 
geholfen.
Gruß
An den rest geht mein herzliches Beileid!

von Ralph (Gast)


Lesenswert?

Thomas D. schrieb:
> das die hw fertig ist und nicht von mir ist... ich setze nur den mc auf
> die pcb. Daher bin ich an das pinning und an die randbeschaltung
> gezwungen.

Und genau das ist immer wieder das gleiche Problem.

Irgendein Hardware Spezi macht eine Platine und wirft die den Software 
Leuten vor die Füße mit dem Kommentar, "hier ist fertig jetzt mach mal, 
Änderungen gibt es keine".

Eigentlich müsste mal als Softareentwickler das Teil zurückwerfen mit 
dem Kommentar "Das ist Müll, nochmal von vorne, aber dann richtig"


Ist das denn SOOO schwer das die Hardwareentwickler ( oder Einkäufer, 
die sind noch schlimmer) mit den Softwareentwicklern reden BEVOR die 
Hardware gebaut ( gekauft) wird.

von Der (Gast)


Lesenswert?

Thomas D. schrieb:
> Das Problem ist mittlerweile gelöst, läuft alles wunderbar.

Was war das Problem?

von Hack K. (hackerfleisch)


Lesenswert?

@Der

Das Problem war wie vermutet, dass in der ISR zu viele unterfunktionen 
aufgerufen wurden.
z.b. zwei mal ReadSRAM, PowerOff(), etc..
Ich bin mir nicht sicher, aber ich vermute, dass wenn die ISR eine 
andere Methode aufruft die auch von anderen Methoden in der Main 
aufgerufen werden können, hat es geknallt.
Ja, ich habe alle wichtigen variablen mit volatile deklariert.

Nach dem ich die eigentliche funktion vom auslesen des SRAM in die ISR 
direkt geschrieben habe, komme ich locker untrer die kritischen 200µs 
(sind jetzt ca. 170µs). D.h. alleine 3 funtionen aufzurufen, hatte ca. 
30µs gedauert, zumindest roh im c code gesehen. Was der comiler dann 
daraus gemacht hat, kann ja was ganz anderes sein. Optimierungsstufe war 
O1. Momentan benutze ich O3.

@Ralph
Da gebe ich Dir voll und ganz recht! Ich hätte auch lieber einen µC mit 
Speicheranbindung genommen, dazu die Spannung nicht mit einer 
PulsPausenModulation und Tiefpässe 6er Ordnung geglättet, sondern eine 
art 10 oder 12 Bit 2R2 Netzwerk genommen.
Oder gleich einen µC mit Speicheranbindung UND D/A wandler, dann wäre 
das alles viel einfacher.

Gruß
Thomas D.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Thomas D. schrieb:
> eine andere Methode aufruft
Eine Methode also. Früher was das in C noch eine simple Funktion...

> komme ich locker untrer die kritischen 200µs (sind jetzt ca. 170µs).
Du hast 85% Prozessorauslastung und sagst "locker"?
Warum brauchst du so lange?
Was läuft da schief?
Interessiert dich das nicht?

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:

> Warum brauchst du so lange?
> Was läuft da schief?
> Interessiert dich das nicht?

Scheint nicht so zu sein.
Bei 16Mhz hat er eine Taktzeit von 0.0625 µs
Dauert die ISR 170µs, dann verbrutzelt er in der ISR 2720 Takte. Ein 
gesunder Mix aus Assembleranweisungen vorausgesetzt sind das über den 
Daumen irgendwas bei 2200 Instruktionen. Der SRAM Zugriff braucht, 
wieder über den Daumen und extrem wohlwollend geschätzt, davon ca. 20 
bis 40. Wo kommen die restlichen 2100 Instruktionen her? Das ein 
Funktionsaufruf ein paar Takte kostet, Register sichern und 
wiederherstellen .... alles geschenkt. Klar kostet das was, aber das 
sind keine 2000 Instruktionen.


Irgendwas stimmt da nicht.
Und nicht zuletzt hab ich schön langsam den Verdacht, dass die 16Mhz in 
Wirklichkeit nur 1Mhz sind und/oder es irgendwo Floating Point en mass 
gibt, die er nicht zeigt.

Das hier
> D.h. alleine 3 funtionen aufzurufen, hatte ca. 30µs gedauert,
ist keine Erklärung. bzw. nur dann, wenn man beide Augen zukneift. Denn 
3 Funktionsaufrufe sind bei 16Mhz nie und nimmer für 30µs 
verantwortlich. Das sind 480 Takte. 160 pro Aufruf.


Und bei den Zahlen wage ich die Prognose: wir werden noch mal von ihm 
hören.

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.