Skocz do zawartości

Problem z czasem zapisu na kartę SD STM32 F746


Pomocna odpowiedź

Napisano

Witam,
od dłuższego czasu próbuję napisać program który odczytywał by wartości z ADC (częstotliwość min 1K na kanał, z jak największej liczby kanałów) i zapisywał czas uzyskania i wartość na karcie w postaci pliku txt. Wszystko było by ok gdyby nie przerwa podczas przepełnienia bufora karty i konieczność odczekania 2[ms] na zapis bufora na karcie.

Wygląda to miej więcej tak, że przed 10[ms] wszystko jest ok po czym następuje przerwa 2[ms] i znowu jest ok. Chciałbym zapisywać na karcie ok 5 min.

Czy ktoś ma pomysł jak rozwiązać ten problem ?

Dodam że dopiero zaczynam moją przygodę z tego typu układami (STM32) prosił bym o pomoc jak dla całkowicie zielonej osoby.

#include "mbed.h"
#include "TS_DISCO_F746NG.h"
#include "LCD_DISCO_F746NG.h"
#include "SDFileSystem.h"
#include <stdio.h>

DigitalOut myled(LED1);
InterruptIn user(USER_BUTTON);
LCD_DISCO_F746NG lcd;
TS_DISCO_F746NG Ts;
TS_StateTypeDef TS_State;
Timer timer;

SDFileSystem sd("sd");
FILE *fp;


AnalogIn ANALOG_0(A0);
AnalogIn ANALOG_1(A1);
AnalogIn ANALOG_2(A2);
AnalogIn ANALOG_3(A3);
AnalogIn ANALOG_4(A4);
AnalogIn ANALOG_5(A5);

uint16_t x, y;
uint8_t text[30];
uint8_t status;

uint8_t pomiar_start=0;

uint32_t time_us=0;
char buffer_time [10];
char buffer_0 [10];
char buffer_1 [10];
char buffer_2 [10];
char buffer_3 [10];
char buffer_4 [10];
char buffer_5 [10];

uint8_t ANALOG_0_ON=0;
uint8_t ANALOG_1_ON=0;
uint8_t ANALOG_2_ON=0;
uint8_t ANALOG_3_ON=0;
uint8_t ANALOG_4_ON=0;
uint8_t ANALOG_5_ON=0;

void display_analog_on(void);
void pomiar_on_of(void);
void pomiar_pokaz(void);
void pomiar_zapis(void);
void check_SD(void);


int main()
{
   lcd.Clear(LCD_COLOR_BLUE);
   lcd.SetBackColor(LCD_COLOR_BLUE);
   user.fall(&pomiar_on_of);

   lcd.SetTextColor(LCD_COLOR_RED);
   lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"ANALOG_0", CENTER_MODE);
   lcd.DisplayStringAt(0, LINE(2), (uint8_t *)"ANALOG_1", CENTER_MODE);
   lcd.DisplayStringAt(0, LINE(4), (uint8_t *)"ANALOG_2", CENTER_MODE);
   lcd.DisplayStringAt(0, LINE(6), (uint8_t *)"ANALOG_3", CENTER_MODE);
   lcd.DisplayStringAt(0, LINE(8), (uint8_t *)"ANALOG_4", CENTER_MODE);
   lcd.DisplayStringAt(0, LINE(10), (uint8_t *)"ANALOG_5", CENTER_MODE);

   sd.mount();
   check_SD();

   while(1) {
       display_analog_on();
       if(pomiar_start == 1) {
           //pomiar_pokaz();
           pomiar_zapis();


       }
   }//koniec while(1)
}//koniec main


void check_SD(void)
{

   fp = fopen("/sd/emg.txt", "w");
   if (fp == NULL) {
       lcd.SetTextColor(LCD_COLOR_RED);
       lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"SD_ERROR", LEFT_MODE);
   } else {
       lcd.SetTextColor(LCD_COLOR_GREEN);
       lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"SD_OK", LEFT_MODE);
   }
   //fclose(fp);
}// koniec check_SD();


void pomiar_on_of(void)
{
   pomiar_start=!pomiar_start;
}//koniec pomiar()

void pomiar_pokaz(void)
{
   timer.start();
   time_us=timer.read_us();
   sprintf((char*)text, "time=%d [ms]", time_us);
   lcd.DisplayStringAt(0, LINE(7), (uint8_t *)&text, CENTER_MODE);

   sprintf((char*)text, "ADC_0=%d [ms]", ANALOG_0.read_u16());
   lcd.DisplayStringAt(0, LINE(1), (uint8_t *)&text, LEFT_MODE);
   sprintf((char*)text, "ADC_1=%d [ms]", ANALOG_1.read_u16());
   lcd.DisplayStringAt(0, LINE(2), (uint8_t *)&text, LEFT_MODE);
   sprintf((char*)text, "ADC_2=%d [ms]", ANALOG_2.read_u16());
   lcd.DisplayStringAt(0, LINE(3), (uint8_t *)&text, LEFT_MODE);
   sprintf((char*)text, "ADC_3=%d [ms]", ANALOG_3.read_u16());
   lcd.DisplayStringAt(0, LINE(4), (uint8_t *)&text, LEFT_MODE);
   sprintf((char*)text, "ADC_4=%d [ms]", ANALOG_4.read_u16());
   lcd.DisplayStringAt(0, LINE(5), (uint8_t *)&text, LEFT_MODE);
   sprintf((char*)text, "ADC_5=%d [ms]", ANALOG_5.read_u16());
   lcd.DisplayStringAt(0, LINE(6), (uint8_t *)&text, LEFT_MODE);

}


void pomiar_zapis(void)
{
   timer.start();
   while (time_us<=1000000) {

       timer.reset();

       //fp = fopen("/sd/emg.txt", "w");



       time_us=timer.read_us();

       sprintf(buffer_time, "%d", time_us);
       fprintf(fp, buffer_time);
       fprintf(fp,";");

       if (ANALOG_0_ON == 1) {
           sprintf(buffer_0, "%d", ANALOG_0.read_u16());
           fprintf(fp, buffer_0);
           fprintf(fp,";");
       } else {
           fprintf(fp, "0;");
       }
       if (ANALOG_1_ON == 1) {
           sprintf(buffer_1, "%d", ANALOG_1.read_u16());
           fprintf(fp, buffer_1);
           fprintf(fp,";");
       } else {
           fprintf(fp, "0;");
       }
       if (ANALOG_2_ON == 1) {
           sprintf(buffer_2, "%d", ANALOG_2.read_u16());
           fprintf(fp, buffer_2);
           fprintf(fp,";");
       } else {
           fprintf(fp, "0;");
       }
       if (ANALOG_3_ON == 1) {
           sprintf(buffer_3, "%d", ANALOG_3.read_u16());
           fprintf(fp, buffer_3);
           fprintf(fp,";");
       } else {
           fprintf(fp, "0;");
       }
       if (ANALOG_4_ON == 1) {
           sprintf(buffer_4, "%d", ANALOG_4.read_u16());
           fprintf(fp, buffer_4);
           fprintf(fp,";");
       } else {
           fprintf(fp, "0;");
       }
       if (ANALOG_5_ON == 1) {
           sprintf(buffer_5, "%d", ANALOG_5.read_u16());
           fprintf(fp, buffer_5);
       } else {
           fprintf(fp, "0");
       }
       fprintf(fp, ";\r\n");







       wait_us(500);
   }

   fclose(fp);
   pomiar_start=0;
   lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"DONE", RIGHT_MODE);


}//koniec pomiar_zapis();


void display_analog_on(void)
{
   Ts.GetState(&TS_State);

   if (TS_State.touchDetected) {
       x = TS_State.touchX[0];
       y = TS_State.touchY[0];
       //sprintf((char*)text, "x=%d y=%d    ", x, y);
       //lcd.DisplayStringAt(0, LINE(10), (uint8_t *)&text, LEFT_MODE);


       if (x >= 160 && x<=320 && y >= 1 && y <= 40) {
           ANALOG_0_ON = !ANALOG_0_ON;
           if (ANALOG_0_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"ANALOG_0", CENTER_MODE);
           }
           if (ANALOG_0_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(0), (uint8_t *)"ANALOG_0", CENTER_MODE);
           }
       }
       if (x >= 160 && x<=320 && y >= 41 && y <= 80) {
           ANALOG_1_ON = !ANALOG_1_ON;
           if (ANALOG_1_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(2), (uint8_t *)"ANALOG_1", CENTER_MODE);
           }
           if (ANALOG_1_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(2), (uint8_t *)"ANALOG_1", CENTER_MODE);
           }
       }
       if (x >= 160 && x<=320 && y >= 81 && y <= 120) {
           ANALOG_2_ON = !ANALOG_2_ON;
           if (ANALOG_2_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(4), (uint8_t *)"ANALOG_2", CENTER_MODE);
           }
           if (ANALOG_2_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(4), (uint8_t *)"ANALOG_2", CENTER_MODE);
           }
       }
       if (x >= 160 && x<=320 && y >= 121 && y <= 180) {
           ANALOG_3_ON = !ANALOG_3_ON;
           if (ANALOG_3_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(6), (uint8_t *)"ANALOG_3", CENTER_MODE);
           }
           if (ANALOG_3_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(6), (uint8_t *)"ANALOG_3", CENTER_MODE);
           }
       }
       if (x >= 160 && x<=320 && y >= 181 && y <= 220) {
           ANALOG_4_ON = !ANALOG_4_ON;
           if (ANALOG_4_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(8), (uint8_t *)"ANALOG_4", CENTER_MODE);
           }
           if (ANALOG_4_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(8), (uint8_t *)"ANALOG_4", CENTER_MODE);
           }
       }
       if (x >= 160 && x<=320 && y >= 221 && y <= 272) {
           ANALOG_5_ON = !ANALOG_5_ON;
           if (ANALOG_5_ON == 0) {
               lcd.SetTextColor(LCD_COLOR_RED);
               lcd.DisplayStringAt(0, LINE(10), (uint8_t *)"ANALOG_5", CENTER_MODE);
           }
           if (ANALOG_5_ON == 1) {
               lcd.SetTextColor(LCD_COLOR_GREEN);
               lcd.DisplayStringAt(0, LINE(10), (uint8_t *)"ANALOG_5", CENTER_MODE);
           }
       }
       wait_ms(300);
   }

} //koniec display_analog_on();

Program działa następująco

Włączam mikro(sprawdzenie obecności karty) po czym na ekranie wybieram ADC których chcę odczytywać wartości, następnie przycisk i 10 s. Wyświetla się napis"DONE" po zakończeniu zapisu wyciągam kartę wrzucam w czytnik i uzyskuję czasy pomiędzy danymi próbkami"

565

556

556

556

555

556

556

556

555

556

556

556

18187(to miejsce problemu z którym nie mogę sobie poradzić)

557

555

556

556

556

557

557

556

556

556

5287

Spotkałem się gdzieś z podobnym problemem. Winna może być karta SD i to w jaki sposób buforuje sobie dane do zapisu.

Jakiej karty teraz używasz? Testowałeś inne karty?

O ile zużycie pamięci to nie problem to buforuj sobie dane i zapisuj jakieś większe paczki.

Czyli np. możesz mieć bufor 1000 danych po 2 bajty = 2000 bajtów pamięci * 2 i najpierw czytasz 1000 próbek do bufora 1, potem zmieniasz ustawienia dma na bufor 2, a bufor 1 zapisujesz w całości na kartę... jak bufor 2 dojdzie do końca zmieniasz dma na bufor 1, a bufor 2 zapisujesz w całości na kartę i tak cały czas. Wielkość bufora zależy od szybkości karty ( w tym przypadku przy 1000 próbek na sekundę zapis 2kB na kartę może trwać do sekundy... albo możesz zapisywać dane z 10 adc przez 100ms )..

PS. używanie sprintf/fprintf jest wolne - zamiast tego napisz własną funkcję zmieniającą wartość pomiaru na odpowiedni tekst.

Kartę mam SanDisk (10), wiem że podczas zapisu na karcie przy przepełnieniu jej bufora(512) karta wchodzi tak jakby w trym zapisu bufora w pamięci przez co występuje ta przerwa. Próbowałem buforować więcej danych do 100 próbek mieściłem się jeszcze w zadanym 1k na kanał.

Nie bardzo rozumiem jeszcze jak używać tego dma,(wiem na czym to polega, czytałem artykuł o tym) jak wygląda kod do użycia tego "systemu".

używanie sprintf/fprintf jest wolne- możliwe, ale dla mnie wystarczająco gdyby nie ta przerwa 2ms dało radę uzyskać ok 10k na kanał (przynajmniej tak mi się wydaje).

  • 2 tygodnie później...

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...