Sperrt f16_blockwrite Interrupts?

  • 1
  • 2
  • Page 1 of 2
Lschreyer
Schreiberling
Avatar
Gender: n/a
Posts: 526
Registered: 02 / 2007
Subject:

Sperrt f16_blockwrite Interrupts?

 · 
Posted: 15.01.2012 - 20:10  ·  #1
Hallo allerseits,

ich habe ein Problem mit dem Zugriff auf eine SD-Card in einer INterruptroutine.

Ich setze einen Mega1284p ein, 16 Mhz, 5V, Timer 3 wird dabei so eingestellt, dass alle 1 ms der
Interrupt TIMER3COMPA; aufgerufen wird.
Klappt auch alles gut.

In der Routine wird ein A/D-Wert abgerufen, die Daten sollen dann auf die SD-Card geschrieben werden. Das geht auch, nur scheint sich der Controller zu "verhaspeln". Ich konnt noch keinen Grund dafür finden, daher versuche ich es mal hier.

Ich öffne die Datei auf der SDcard und schreibe dann im Interrupt Daten hinein.
Wenn RECTIME beio 10.000 angekommen ist schließe ich die Datei wieder.

Die Routine ist:

Interrupt TIMER3COMPA;
begin
if REC then
excl(LED1);
ADC_AVERAGE; // Speichert die Daten in "Dataset", 16 Bytes
RECTIME:= RECTIME + 1;
f16_blockwrite(fd, @Dataset, sizeof(Dataset), res);
incl(LED1);
endif;
end;


Außerhalb der Routine ist dann noch:

loop
....

if (RECTIME >= 10000) then
RECSTOP:= true;
closesdcard;
endif;
endloop;

Das schließt die Datei.


Ohne das f16_blockwrite habe ich sauber alle 1 ms einen Interrupt.
Mit der Routine auch, nur alle paar tausend Zugriffe ist auf dem Oszi auf einmel eine Reihe von Verzögerungen zu sehen, dann läuft es weiter, wenn auch nicht mehr so gleichmäßig wie ohne f16_blockwrite..
Was könnte diese Verzögerungen bzw. Ungleichmäßigkeiten auslösen? Sperrt der Treiber den Interrupt?

Ich teste das immer mit einem Port (hier LED1) den ich toggle. Da kann man per Oszi schön sehen was sich zeitmäßig tut.


Wenn ich ohne den Interrupt in die Datei schreibe läuft es ohne Verzögerungen, 27 µs pro Datentransfer, also normal viel Zeit in der 1ms die ich im Interrupt habe, also zu langsam scheint sie nicht zu sein.

Bin wirklich ratlos...

Louis
mc-electronic
Benutzer
Avatar
Gender: n/a
Location: Sauerland NRW
Posts: 372
Registered: 03 / 2008
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 16.01.2012 - 08:44  ·  #2
Hallo Louis,

der Blockwrite sperrt keine Interrupts. 16 Bytes mal 10.000 msec sind viel Holz in kurzer Zeit. Im Interrupt auf die SD-Card zu schreiben halte ich auch für gewagt - ich denke, daß es Timing-Probleme sind. Die Karte schafft eine Weile die Geschwindigkeit, aber je nach dem, wohin die Daten geschrieben werden (über Sektorgrenzen hinweg), kann das möglicherweise auch mal länger als 1 ms dauern. Dann werden die Interrupts nicht mehr zeitgerecht abgearbeitet.

Versuch folgendes:

1. Das File nur dann schließen, wenn der Interrupt nicht dazwischen schreiben kann. Das ist. m.E. nicht gewährleistet.
2. Lege das Datenfile vorher in der nötigen Größe mit F16_FileCreate an. Schreibe dann mit F16_BlockRandomWrite. Das geht viel schneller als mit F16_Blockwrite.
3. Teste das Programm mit einer langsameren Frequenz im Interrupt als 1 kHz. Dann kannst Du besser mitverfolgen, wann es anfängt, kritisch zu werden.

Gruß, Michael
Lschreyer
Schreiberling
Avatar
Gender: n/a
Posts: 526
Registered: 02 / 2007
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 16.01.2012 - 11:30  ·  #3
Hallo,

ich habe beobachtet, dass es im Interrupt ca. alle 3-5 Sekunden zu so einer Unterbrechung kommt. Die Kontroll-LED leuchtet dann 2-3x länger auf, dann gehts weiter. Man sieht an dem Blinken auch sofort, dass da eine starke Unregelmäßigkeit da ist. Das Bild auf dem Oszi ist recht chaotisch, das 1ms-Timing wird da nicht mehr eingehalten.

Da dachte ich, dass die SD Card evtl. Verwaltungsaufgaben durchführt, das Dateisystem aktualisiert o. ä. Also habe ich den Test gemacht:
Wenn ich ohne den Interrupt 20.000 Datensätze so schnell wie möglich reinschreibe klappt das ohne die Unterbrechung. Die SD-Card nimmt die Daten dann schön gleichmäßig an. Das kann es also nicht sein, die Karte packt es.

Auch ein Timerwechsel bringt nichts. Der Schreibvorgang ist auch nur sehr kurz, das passt locker in die 1 ms. Insgesamt habe ich mit A/D Sampling unter 100µs gemessen, es bleiben also noch 900 µs übrig.

16 Bytes mal 1000 sind nur 16 Kb / sekunde, das sollte die Karte locker schaffen. Tut sie auch wenn ich den Test mache, nur im Interrupt klappts nicht.

Ich werde wohl einen Zwischenspeicher in Form eines Flashs einsetzen, dass klappt erfahrungsgemäß sehr gut. Mich wundert nur warum es nicht geht, sonst läuft auf dem Controller nichts, nur der Messinterrupt und die Speicherung.

Ich werde heute noch mal die andere Schreibstrategie probieren, bin gespannt...

Louis
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 16.01.2012 - 12:10  ·  #4
Doing everything in interrupt is risky and leads to the problems you have described. Instead you could make two arrays (one for actual storage and standby one that will be used for writing to card) with storage enough for 1000 readings. Then in interrupt you read ADC and store it in actual array. Once 1000 readings are done you just flip in interrupt actual and standby arrays and flag this event. Then main loop, or some other process polls this flag in a loop and when it finds it to be true it writes standby buffer with all 1000 readings to the card. This single write to the card is fast and you do not experience interrupt problems and dropped readings. Online translation sucks and I couldn't understand everything, but in your particular example, it looks like interrupt might try to save when file is closed. You could test it by disabling interrupts before closesdcard and enabling it right after it. Also your interrupt routine might be longer then expected if you have multitasking enabled or systick fights with your interrupt for time. Then OnSysTick() might help instead of interrupt. In case you have concurrent access to the same variable from both interrupt and main loop then you might want to investigate LOCKED keyword in compiler manual. Anyway, whatever you do try to avoid slow things like f16_blockwrite() in interrupts (and also in SysTick).
Lschreyer
Schreiberling
Avatar
Gender: n/a
Posts: 526
Registered: 02 / 2007
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 16.01.2012 - 18:16  ·  #5
Thank you for your ideas. I just tried the buffered write, to no avail :-(

I made two RAM buffers, each holding 100*16 bytes of data.
In the interrupt I write data to the buffers, in the main loop I wait for the flag and write out the last filled buffer to the SD Card.
This works for a few seconds, than I suddenly again have the interruption of the write process, for 2-3 write cylces it slows down, then goes up again with the old speed.

If I switch off the interrupt and write 1 MB of data to a file on the card, it works perfect... Very strange thing.
Also a very slow interrupt of 10 ms is not better. Using F16_BlockRandomWrite is also not better.

I have
SysTick, SerPort, ADCPort, LCDmultiPort, BeepPort, TWImaster, SPIdriver, FAT16, Switchport_G;

I switched off some of these already, no help either.

Louis
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 17.01.2012 - 11:08  ·  #6
As I have already said, Systick and Interrupt might fight for time. You can check this if you use prime numbers for their periods (with reasonably big their smallest common divider). If this is the case, then using prime numbers should manifest as having a longer period without slowdown, and then after some more time you have a slowdown when they finally fight. If this is the case, you could move interrupt code to OnSysTick() function and kill interrupt usage completely (if you set your SysTick to 1ms). That will solve the fight. If you have enough RAM then you could also make buffers as big as possible. Also remember that ADC is not constantly free running and instead it is read in the background in SysTick, so most probably your ADC_AVERAGE does not make sense if you are reading values faster then SysTick (unless you are reading yourself ADC directly without using AvrCo's built in ADC functions).

You usage of Beep, LCD, debounced switches and TWI/SPI might also interfere and make this "slowdown" you are facing, since these drivers might use SysTick (and prolong it) or interrupts themselves. I suggest you clean your code to exclude all of them and just make a simple test which will do 1 million writes to the new file on the card and when finished stop, close file, and lit a led. Then you will take out the card and check on PC by simple counting if you have all readings or something is dropped. You can also use some output pins to monitor periods on your scope for irregularities. This method will show you what is 100% good and working, and you may add things one by one and see where your problem is.

Without seeing complete code we can only guess, but If everything else fails, and you can change your logic, then you can use something like this as a workaround (make SysTick 0.5):
Code
loop
     if isSysTimerZero(SecTimer) then
       SetSysTimer(SecTimer, 2);       // 2 x 0.5 = 1 milisecond
       // put here what you want to do each milisecond
     endif;
endloop;

No interrupts, everything in main loop. Not as accurate as timer interrupt but close enough.
Lschreyer
Schreiberling
Avatar
Gender: n/a
Posts: 526
Registered: 02 / 2007
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 17.01.2012 - 12:11  ·  #7
I tried that also, a simple systimer, set to 5 ms, so lots of time to write the 16 bytes to the card.
Same result. Every 3-4 seconds it slows down, even with the pre-created file and writes with randomblockwrite.

I do not poll the internal AD, but an external 16 bit A/D on the SPI Port.

I will set up a testprogram with only the sampling and sd card writes. Report will follow ;-)
If it still fails I will post the complete code.

L?ouis
Lschreyer
Schreiberling
Avatar
Gender: n/a
Posts: 526
Registered: 02 / 2007
Subject:

Re: Sperrt f16_blockwrite Interrupts?

 · 
Posted: 17.01.2012 - 15:16  ·  #8
Here is the testprogramm, striped from everything but the beepport (I tried to let that away too, not better, so I kept it).

Code
program test1284;

Device = mega1284P, VCC = 5;

Define_Fuses
  SPIclk         = 1000000;
  NoteBook       = A;
  COMport        = USB;
  LockBits0      = [];
  ProgMode       = SPI; // SPI, JTAG or OWD
  ProgFuses      = true; // or false – program Fuse Bits (* REV4 *)
  ProgLock       = true; // or false – program Lock Bits (* REV4 *)
  ProgFlash      = true; // or false – program Flash (* REV4 *)
  ProgEEprom     = FALSE; // or false – program Eeprom (* REV4 *)

Import SysTick, BeepPort, SPIdriver, FAT16; //, Ticktimer;
From System Import LongInt, longword, Float;

Define
  ProcClock      = 16000000;       {Hertz}
  SysTick        = 1, timer0;             {msec}

  StackSize      = 100, iData;
  FrameSize      = 200, iData;
  BeepPort       = PortB, 2;

  SPIorder       = MSB;
  SPImode        = 3;
  SPIpresc       = 3; // presc = 0..3 -> 4/16/64/128
  SPI_SS         = FALSE; // don’t use SS pin as chipselect

  FAT16          = MMC_SPI, iData;
  F16_MMCspeed   = slow;
  F16_FileHandles = 1;
  F16_DirLevels  = 2;


uses UFAT16;


Implementation

function ADC_AVERAGE : Float; Forward;

{$IDATA}
type

  //Dataset ist ein Datensatz der alle Daten enthält.
  Datasetrec     = Record  // 16 bytes
                     Time           : Word;
                     adc0, adc1     : Word;
                     ad1, ad2, ad3, ad4, ad5: Word;
                   end;

  Recdatarec     = Record
                     samples        : Word;
                     Scalemode      : Byte;
                     Tara           : Float;
                   end;

  FileCNT_Type   = Record     // Für die Datei auf der SD-Card, enthält die letzte Dateinummer
                     lastnumber     : Word;
                   end;


Var
  Tara           : Float;
  ADC0AVG, ADC1AVG     : Float;  // Mittelwerte aus gleitendem Filter
  adc0, adc1     : Word;
  Scalemode      : Byte;
  Waittime       : Byte;
  RECTIME        : Word;
  REC, RECSTOP   : Boolean;  // REC schaltet die Speicherung ein, RECSTOP wieder aus.
  fc             : File of FileCNT_Type;
  fd             : File of Byte;
  fcdata         : FileCNT_Type;
  rd             : Recdatarec;
  Recdata        : Recdatarec;
  Dataset        : Datasetrec;
  res            : Word;
  filecount      : Word;
  samples, scount      : Word;
  SDCardFound    : Boolean;

  SPIinUSE       : Boolean;
  LED1[@PORTC, 3]      : Bit;
  SD_CS[@PORTB, 1]     : Bit;
  ADCONV[@PORTD, 2]    : Bit;
{$IDATA}



function GetGSensorADC(ch : BYte) : Word;
var  w1, w2     : byte;
  ADCValue       : Word;
begin
  EXCL(ADCONV);
  udelay(1);
  INCL(ADCONV);
  udelay(1);  // Conversion time up to 4 µs*)
  EXCL(ADCONV);
  nop;
  nop;
  nop;

  if ch = 0 then
    w2:= SPIinoutbyte(%10000000);   // CH0
  else
    w2:= SPIinoutbyte(%11000000);   // CH1
  endif;

  w1:= SPIinpbyte; // 2. Byte abrufen
  INCL(ADCONV);    // Fertig

  lo(ADCValue):= w1;
  hi(ADCValue):= w2;
  
  return(ADCValue);
end;


function ADC_AVERAGE : Float;  // Gets channel 0 and 1 of the A/D and saves the result in ADC0AVG / ADC1AVG
begin
  SPIINUSE:= TRUE;
  ADC0:= GetGSensorADC(1);
  udelay(1);
  ADC1:= GetGSensorADC(0);
  SPIINUSE:= FALSE;

  ADC0AVG:=Float(ADC0);
  ADC1AVG:=Float(ADC1);
  return(ADC1AVG);
end;





Interrupt TIMER2COMPA;
begin
  if REC AND (RECTIME < samples) then
    excl(LED1);
    RECTIME:= RECTIME + 1;
    Dataset.Time:= RECTIME;      // Fill dataset with some dummy data
    Dataset.adc0:= adc0;
    Dataset.adc1:= adc1;
    f16_blockwrite(fd, @Dataset, sizeof(Dataset), res);  // write to SD Card
    incl(LED1);
  else
    if not SPIinUSE then
      ADC_AVERAGE;
    endif;
  endif;

end;


Procedure onFAT16_SS; // Chipselect  activator
begin
  if _ACCA = 0 then
    excl(SD_CS);
  else
    incl(SD_CS);
  endif;
end onFAT16_SS;


function OPENSDCARD : Boolean;
Var go: Boolean;
  i, Fileversion : Byte;
begin
  if not SPIinUSE then
  repeat until SPIinUSE = FALSE;
  endif;
 
 SPIinUSE:= true;

  go:= FALSE;
  beepsiren(0, 1);
  if f16_diskinit
  then
    f16_diskreset;
    if f16_checkdisk then
      f16_changedir('\');
      go:= true;
      if not f16_pathexist('\MOTOR') then
        go:= f16_createdir('\', 'MOTOR', 0, 0);
      endif;
      go:= f16_changedir('\MOTOR');

      beepout(1200, 100);
      if go then
        // Check if filecount file is there...
        if not f16_fileexist('', 'filecnt.dat', faanyfile) then
          filecount:= 0;
        else
          if F16_Fileassign(fc, '', 'filecnt.dat') then
            f16_filereset(fc);
            f16_blockread(fc, @fcdata, sizeof(fcdata), res);
            filecount:= fcdata.lastnumber + 1;
            f16_fileclose(fc);
          endif;
        endif;
        beepout(1000, 100);

        // Create a new file and write header data
        Recdata.samples:= samples;
        Recdata.Scalemode:= Scalemode;
        Recdata.Tara:= Tara;

        if F16_Fileassign(fd, '', 'F' + inttostr(filecount) + '.MOT')
        then
          go:= f16_filerewrite(fd, [faArchive], 0, 0);
          Fileversion:= 2;
          go:= f16_blockwrite(fd, @FileVERSION, 1, res);
          go:= f16_blockwrite(fd, @Recdata, sizeof(Recdata), res);   // Write header
          beepout(800, 100);

          go:= f16_blockwrite(fd, @Dataset, sizeof(Dataset), res);  // Write first dataset
          mdelay(10);
          RECTIME:= 0;
          REC:= true; // Start saving data in INterrupt
          SPIinUSE:= FALSE;
        endif;
        beepout(600, 100);

      endif;
    endif;
  endif;
  SPIinUSE   :           = FALSE;
  return(go);
end;




function CloseSDCard : Boolean;
Var go: Boolean;
  i, Fileversion : Byte;
begin
  if not SPIinUSE then
  repeat until SPIinUSE = FALSE;
  endif;

  if RECSTOP then
    SPIinUSE:= true;
    REC:= FALSE;
    RECSTOP:= FALSE;

    go:= f16_fileclose(fd);    // Close file
    // Write new filecount-file ...
    if F16_Fileassign(fc, '', 'filecnt.dat') then
      f16_filerewrite(fc, [], 0, 0);
      fcdata.lastnumber:= filecount;
      f16_blockwrite(fc, @fcdata, sizeof(fcdata), res);
      f16_fileclose(fc);
    endif;
    beepsiren(0, 3);
    RECTIME:= 0;

    SPIinUSE:= FALSE;
    return(go);
  endif;
end;





Procedure InitPorts;
begin
  PortA:= %11000000;   // 1 = Pullup!!  // Letzte 3 Bits sind Erkennung ob SD, Mini oder Micro
  DDRA:=  %00000000;   // 0= input, 1= Output

  PortB:= %00000010;   // 1 = Pullup!!
  DDRB:=  %11111111;   // 0= input, 1= Output

  PortC:= %00010000;
  DDRC:=  %11111100;

  PortD:= %00000000;
  DDRD:=  %11111111;

end InitPorts;


Procedure Init;
begin
  REC:= FALSE;
  RECTIME:= 0;
  Scalemode:= 100;
  samples:= 20000; // 10 Sekunden
  SPIinUSE:= FALSE;

  // Set all chiposelects to default values
  incl(ADCONV);
  incl(SD_CS);
  SDCardFound:= FALSE;

  if not SPIinUSE then
   repeat until SPIinUSE = FALSE;
  endif;

  // SD CARD TESTEN UND INIT
  // SDCARD testen?
  if f16_diskinit
  then
    f16_diskreset;
    mdelay(100);
    if f16_checkdisk then
     mdelay(100);
      // Jetzt Altimax-Ordner anlegen
      f16_changedir('\');
      if not f16_pathexist('\MOTOR') then
        f16_createdir('\', 'MOTOR', 0, 0);
      endif;
      f16_changedir('\MOTOR');
      SDCardFound:= true;
    endif;
  endif;

//TImer 2 starten
  disableints;
  TCCR2A:= %00000010;
  TCCR2B:= %00000101;  // 128 Prescaler
  OCR2A:= 62;   //124 = 1000 sps  62=2000 sps
  TIMSK2:= %00000010;
  EnableInts;


end;



begin
  InitPorts;
  EnableInts;
  INIT;
  beepout(1200, 10);
  
  if SDCardFound then
    opensdcard;  // Open the SD Card, create a file and start writing data
    REC:= true;
  else
    rec:=false;
    beepout(1000, 100);
  endif;
  
  loop
    if REC then 
      if (RECTIME >= samples)then
        TIMSK2:= %00000000;  // Stop Interrupt
        RECSTOP:= true;
        mdelay(100);  // Wait a bit..
        closesdcard;  // Close the sdcard! 
      endif;
    endif;


  endloop;
end test1284.
  • 1
  • 2
  • Page 1 of 2
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   132   146 · Page-Gen-Time: 0.026615s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI