Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:sstv-gen

Generátor SSTV signálu

  • Tomáš Kret
  • xkrett00@stud.feec.vutbr.cz

Zadanie

Implementujte audio generátor pre signál SSTV (slow-scan television), napr. mód Martin M1 alebo Robot B&W. Obrazové data prečítajte z SD karty alebo USB flash disku, signál vygenerujte a odošlite pomocou DAC alebo zvukového kodeku. Overte príjem softwarom MMSSTV.

Úvod

Pre generovanie bol použitý kodek CS43l22 na vývojovej doske stm32f4-discovery. Signál je vzorkovaný frekvenciou 48k. Dáta sú vyčítavané z USB flashdisku naformátovaného na FAT32.

SSTV signál

SSTV je audio signál určený pre prenos obrázkov cez bežné komunikačné zaradenia, jeho frekvencia sa pohybuje od 1500 do 2300 Hz pre data + 1200 Hz pre synchronizačné pulzy. Sú rôzne módy SSTV signálu s charakteristickými parametrami ako je rýchlosť prenosu (riadky obr. za minútu), rozmer obrázku a pod.

Pre tento projekt bol použitý mód Martin M1, ktorý dokáže preniesť obrázok s rozmermi 320×256 pixelov za čas 114s. V móde Martin M1 sú použité 3 druhy synchronizačných signálov: VIS code (vertikálna synchronizácia), horizontálna (scan-line) a oddeľovač farieb.

SSTV prenos začína vertikálnou synchronizáciou VIS code, ktorej formát je: VIS kód Martin módu je 44 v desiatkovej sústave a slúži na označenie nového prenosu ako aj detekciu módu.

Horizontálna synchronizácia označuje začiatok nového riadku, je to signál s frekvenciou 1200 Hz po dobu 4,862 ms.

Ako oddeľovač farieb slúži signál 1500 Hz po dobu 572 us. Jednotlivé pixely sú prenášané periodicky po 458 us. Farbu pixelov predstavuje frekvencia od 1500 Hz (čierna farba) po 2300 Hz (biela farba). U módu Martin je obraz prenášaný po riadkoch sekvenciou G-B-R.

HARDWARE

Ako vývojový kit bol vybratý STM32F4-DISCOVERY osadený mikrokontrolérom STM32F407VG a audio kodekom CS43L22. Voľba vývojového kitu bola ovplyvnená USB perifériou a AUDIO výstupom.

Bloková schéma vývojového kitu: Vybraté parametre STM32F407VG:

  1. frekvencia jadra 168 MHz, 210 DMIPS
  2. MB Flash pamäť
  3. 192 + 4 kB SRAM, z toho 64 KB core-coupled
  4. LCD periféria
  5. 2×12 bit D/A prevodníky
  6. USB OTG full speed PHY
  7. 2x full duplex I2s
  8. 3x I2c

Firmware

Vytváraný bol pomocou STM32CubeMX 4.12 v prostredí Em:Bitz 0.42 a pomocou ďalších podporných knižníc. O generovanie zvuku sa stará audio kodek, do ktorého prúdi DMA stream, kde sa využíva headphone výstup. Harmonický signál je vytváraný pomocou funkcie arm_sin_f32() podporovanej floatovacou jednotkou. Aby sa dosiahla vyššia účinnosť prenosu, je mono signál prerozdelený pre ľavý a pravý kanál.

Vývojový diagram:

Dáta pre prenos sú uložené na flash disku USB, ktorý musí byť naformátovaný na tabuľkovací systém FAT32 kvôli použitej knižnici FATFS. Samotný obrázok je pomocou programu MATLAB prevedený do binárneho formátu pomocou nasledovného skriptu (kde sú už dáta pripravené pre priamy prenos GBR):

clc;
clear all;
close all;
% img = imread('test.png');
img = imread('SSTV.jpg');
imshow(img);
zapis = fopen('SSTVGBR2.bin','w');
% zapis = fopen('SSTVGBR.bin','w');

for j=1:length(img(:,1,1))
    fwrite(zapis,img(j,:,2),'uint8')
    fwrite(zapis,img(j,:,3),'uint8')
    fwrite(zapis,img(j,:,1),'uint8')
end
fclose(zapis);

Významné funkcie v súboru main.c

Vo firmware sa používajú 3 druhy bufferov:

/* USER CODE BEGIN 0 */
static int8_t pol2 = 0;
static int8_t pol1 = 0;
static int16_t wind[2*BUFFER_SIZE] = {0};
static int16_t buffer[4*BUFFER_SIZE] = {0};
static uint8_t RGB[4*BUFFER_SIZE] = {0};

Buffer wind sa odosiela priamo do dma streamu, obsahuje ľavý a pravý kanál okopírovaného z mono signálu. Buffer buffer obsahuje vzorky harmonického signálu, ktorý je vzorkovaný 48000 Hz. RGB obsahuje hodnoty jednolivých pixelov načítaných z USB flash. BUFER_SIZE je stanovené na 4096, čo je hodnota 2n, vďaka čomu je možné realizovať kruhový buffer pomocou logického súčinu &(BUFFER_SIZE-1).

Úryvok časti main:

 /* USER CODE BEGIN 2 */
   BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_AUTO, 70, 48000);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
  /* USER CODE END WHILE */
        MX_USB_HOST_Process();
  /* USER CODE BEGIN 3 */
        if( f_mount( &fatfs,"",0) != FR_OK )
        {
            while(1);
        }
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
        {
            BSP_AUDIO_OUT_Play((uint16_t*)wind, BUFFER_SIZE*2);
            BSP_LED_On(LED4);
            sstv_send();
        }
        HAL_Delay(50);
    }
  /* USER CODE END 3 */

DMA prenos sa v počiatočných podmienkach začne pri prázdnych bufferoch, o naplnení vzorkami sa starajú až funkcie volané funkciou sstv_send(). Funkcia f_mount() priraďuje tabuľkový systém pre knižnicu FATFS. MX_USB_HOST_Process() obsaluhuje USB zbernicu pre enumeráciu, nastavuje stavový automat USB zbernice a pod.

Funkcia sstv_send():

void sstv_send(void) {
    int32_t ln = 0, uk = 0;
    BSP_LED_Off(LED6);
    sstv_init();
    if(f_open(&fp,name,FA_READ)!=FR_OK)
    {
        while(1);
    }/*red data from flash*/
    for (int32_t i=0; i<256; i++){
        if (!(i&16)) {
            f_lseek(&fp, i*960+ln);
            if(f_read(&fp,RGB,4*BUFFER_SIZE,&ret)!=FR_OK)
            {
                while(1);
            }
            uk=0;
        }

        frgen(1200,4842);
        ln = 0;
        while (ln<960) {
            frgen(1500+(RGB[uk])*3.137254902,458);
            if (ln%960==320 || ln%960==640) frgen(1500,750);
            uk++;
            ln++;
        }
    }
    f_close(&fp);
    BSP_LED_On(LED6);
}

Vo funkcii sstv_send() sa rieši odoslanie VIS kódu pomocou funkcie sstv_init(), načítanie ďalších pixelov z USB (funkciou f_read()) posúvaním pointera na súbor uložený vo flash disku (funkciou f_lseek()), generovanie synchronizačných signálov:

  1. frgen(1200,4842); -začiatok nového riadku
  2. if (ln%960==320 || ln%960==640) frgen(1500,750); -oddeľovač farieb
  3. frgen(1500+(RGB[uk])*3.137254902,458); -modulovanie samotných pixelov

Keďže diskrétny signál s periódou vzorkovania 20.83 us neumožňoval nastaviť dobrú synchronizáciu, bolo potrebné upraviť pôvodné hodnoty synchronizačných signálov (miesto 572 ms na 750 ms a miesto 4,862 ms na 4,842 ms).

Funkcia generujúca Vis code pre Martin M1:

void sstv_init(void) {
    frgen(1200,3000000);    //3s test frequency 1200 Hz
    frgen(1900,300000);
    frgen(1200,10000);
    frgen(1900,300000);

    frgen(1200,30000);  //start bit
    frgen(1300,30000);

    frgen(1300,30000);
    frgen(1100,30000);
    frgen(1100,30000);

    frgen(1300,30000);
    frgen(1100,30000);
    frgen(1300,30000);
    frgen(1100,30000);
    frgen(1200,30000);  //stop bit

}

Funkcia generujúca harmonický signál vzorkovaný 48k:

void frgen(int32_t frq, int32_t tm) {
    /*freq[Hz] tm[us]*/
    static int64_t ph = 0;
    static int32_t ind1=0;
    int32_t ind2=0;
    int32_t tmd = 0;
    float32_t tmdel = tmd*(20.833333333);
    while((tmdel<=tm)) {
        float32_t x=2.0*3.141592*(frq*ind2+ph)*0.000020833333333;
        float32_t y=32767.0;
        buffer[ind1] = (int16_t)(arm_sin_f32(x)*y);
        ind1++;
        ind2++;
        tmd++;
        if (ind1 >= BUFFER_SIZE*4) {
            //ind1&=(BUFFER_SIZE*4-1);
            ind1 = 0;
            BSP_LED_On(LED5);
            while(!pol2);
            pol2=0;
            BSP_LED_Off(LED5);
        }
        else if (ind1 == (BUFFER_SIZE*2)) {
            BSP_LED_On(LED3);
            while(!pol1);
        BSP_LED_Off(LED3);
        pol1=0;
        }
        tmdel = tmd*(20.833333333);
    }
    ph += frq*ind2;
}

Funkcia frgen(int32_t frq, int32_t tm) je základná funkcia využívaná generátorom. Generuje harmonický signál s nastaviteľnou frekvenciou a časom dĺžky trvania. Pre SSTV prenos je potrebné zabezpečiť plynulú zmenu kmitočtu - o to sa stará pričítavanie zvyškovej fázy do 64-bitovej premennej ph, ktorá je daná súčinom diskrétneho času s frekvenciou. Premenné typu float32_t alokujú miesto pre float unit a tým úrychľujú výpočet. Buffer pre výpočet vzoriek je rozdelený do dvoch častí pomocou premenných pol 1 a pol2. Kým prebieha výpočet v 1. častu, DMA prenos prebieha v druhej časti a naopak. Buffere sú kruhové. Premenná tmdel sleduje dĺžku generovaného signálu.

Obsluha prerušenia na koniec DMA prenosu:

void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
{
  static int32_t index = 0;
  if(0)
  {
      BSP_AUDIO_OUT_Stop(CODEC_PDWN_HW);
      index = 0;
  }
  else
  {
      static uint8_t ind = 0;
      BSP_AUDIO_OUT_ChangeBuffer((uint16_t*)&wind[0], 2*BUFFER_SIZE);

      index = index + BUFFER_SIZE;
      index &= (BUFFER_SIZE*4-1);
      if (index>=BUFFER_SIZE*2) {
              pol2 = 1;
              pol1=0;
              BSP_LED_Off(LED5);
      }
      else {
            pol1=1;
            pol2=0;
            BSP_LED_Off(LED3);
      }


      pref(index);

  }

}

Wind je kruhový bufer, do ktorého sa nové hodnoty vkladajú až zavolaním funkcie pref(int32_t indx):

void pref(int32_t indx) {
    int ind = 0;
    do {
        wind[(ind*2)&(BUFFER_SIZE*2-1)] = buffer[(ind+indx)&(4*BUFFER_SIZE-1)];
        wind[(ind*2+1)&(BUFFER_SIZE*2-1)] = buffer[(ind+indx)&(4*BUFFER_SIZE-1)];
        if ((ind+indx)>(4*BUFFER_SIZE-1)) BSP_LED_Off(LED4);
        else if ((ind+indx)<(2*BUFFER_SIZE-1)) BSP_LED_On(LED4);
        ind++;

    } while ((ind*2+1)<=(2*BUFFER_SIZE+buf));

}

Funkcia pref(int32_t indx) slúži na duplikovanie vzoriek do oboch kanálov. Hodnoty bufferov sa načítavajú a zapisuju cyklicky, čím sa predpočítajú prvky do ďalšieho kroku.

Celý firmware pre EmBitz tu.

Súbory uložené na USB flash disku tu.

Overenie funkčnosti

                                            Testovacie podmienky

                   Výsledky prenosov (vpravo synchronizačné signály) a porovnanie s originálmi

Videozáznam prenosu SSTV

Záver

Na obrázkoch je vidieť, že dochádza k miernemu rozladeniu farieb ako aj synchronizácie, rozladenie môže byť spôsobené vlastnosťami mikrofónu. Synchronizácia by sa mohla zlepšiť pridaním multitaskingu, odstránením blokujúcich čakaní, lepšou synchronizáciou jednotlivých buferov, zvýšením vzorkovacieho kmitočtu a lepším zaokrúhľovaním času. Pre správne načítanie dát z usb po zapnutí treba približne 5 až 10 sekúnd čakať pred stlačením user tlačidla kvôli dokončeniu enumerácie, avšak nie je to nikde signálizované, čo je tiež potrebné vyriešiť.

2015/sstv-gen.txt · Poslední úprava: 2016/01/26 18:04 autor: Tomáš Kret