Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Sterowanie jasnością wyśw przez DMA stm32f0

norbis15 14 Wrz 2018 23:07 330 11
  • #1 14 Wrz 2018 23:07
    norbis15
    Poziom 14  

    Witam,
    Zrealizowałem prosty wyświetlacz led którego każdy segment ma swoją nóżkę w procesorze. Sterowanie jasnością odbywa się za pomocą przerwań timera - po prostu ileś okresów od przerwania do przerwania tego licznika świecą segmenty które mają się świecić, a ileś nie świecą. Ale czy da się to zrobić bez przerywania programu głównego? Na myśl przychodzi mi DMA w trybie pracy cyklicznej, tylko jak miało by to się odbywać? Czy ktoś mógłby mi nakreślić idee jak to mogło by działać?
    Wykorzystany procesor stm32f030 ma 5 kanałów DMA.

    0 11
  • #2 14 Wrz 2018 23:25
    BlueDraco
    Specjalista - Mikrokontrolery

    Da się, zobacz arttykuł w EP z grudnia lub stycznia. Na STM32 można zrealizować sprzętowe sterowanie multipleksowanego wyświetlacza LED bez przerwania timera.

    0
  • #3 15 Wrz 2018 19:09
    norbis15
    Poziom 14  

    Nie mogę znaleźć takiego artykułu... U mnie każdy segment (8 segmentów) jest połączony przez tranzystor z osobnym wyprowadzeniem uC (portu A), w procesorze mam 5 kanałów DMA i 5 liczników (z czego 2 już wykorzystane), jakby każdy licznik generował na nóżkę oddzielny PWM to i tak za mało peryferii.
    Czy jeden kanał DMA może przekazywać dane na cały port GPIO?
    Czy ktoś może mnie nakierować?

    0
  • #4 15 Wrz 2018 19:43
    BlueDraco
    Specjalista - Mikrokontrolery

    Jeśli całe sterowanie wyświetlaczem jest na jednym porcie - potrzebujesz dwóch kanałów DMA (jednego bez regulacji jasności). Zapis z pamięci do rejestru BSRR, tryb cykliczny.

    0
  • #6 15 Wrz 2018 23:22
    BlueDraco
    Specjalista - Mikrokontrolery

    BSRR zawiera BRR, więc w ogólnym przypadu zapis jest zawsze do BSRR, chyba, że zarówno segmenty jak i cyfry są aktywowane tym samym poziomem.

    0
  • #7 16 Wrz 2018 10:40
    norbis15
    Poziom 14  

    Mam anody zasilone na stałe i steruje katodami wszystkimi na porcie A. Rzeczywiście BSRR zawiera BRR i można sterować ledami tylko zapisując rejestr BSRR:

    Code:
    wyswietlanyZnak = znak_;
    
    SEG_A_GPIO_Port ->BSRR = ((((uint16_t) ~znak_) << 16) | ((uint16_t) znak_));

    BlueDraco napisał:
    Jeśli całe sterowanie wyświetlaczem jest na jednym porcie - potrzebujesz dwóch kanałów DMA (jednego bez regulacji jasności).
    BlueDraco czy mógłbyś to rozwinąć? Dobrze myślę, że będę musiał zrobić to jakoś na tablicach dwu wymiarowych?

    0
  • #8 16 Wrz 2018 14:56
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie rozumiem. Czy to jest wyświetlacz multipleksowany? Może byś pokazał schemat?
    Do sterowania wyświetlacza multipleksowanego potrzeba jednego wektora danych 32-bitowych - zawartości BSRR.

    0
  • #9 16 Wrz 2018 16:48
    norbis15
    Poziom 14  

    Nie nie jest multipleksowany, anoda ma na stałe podane napięcie.
    Sterowanie jasnością wyśw przez DMA stm32f0

    Udało mi się zrobić sterowanie jasnością z wykorzystaneim jednego kanału DMA w trybie pracy cyklicznym. Przesyłam do BSRR portu A zawartosć tablicy wartDoRejBSRR o ilości elementów 500 i wypełniam ją, gdy chcę zmienić znak wyświetlany albo poziom jasności, następująco :

    Code:
    uint32_t doRejBSRR = ((((uint16_t) ~znak_) << 16) | ((uint16_t) znak_));
    

       switch (brightness) {               //ządany poziom jasności
          case 0:   okres = 1;      break;
          case 1:   okres = 1;      break;
          case 2:   okres = 2;      break;
          case 3:   okres = 3;      break;
          case 4:   okres = 5;      break;
          case 5:   okres = 7;      break;
          case 6:   okres = 10;   break;
          case 7:   okres = 20;   break;
          case 8:   okres = 30;   break;
          case 9:   okres = 40;   break;
          case 10:   okres = 50;   break;
          case 11:   okres = 100;   break;
          case 12:   okres = 150;   break;
          case 13:   okres = 200;   break;
          case 14:   okres = 300;   break;
          case 15:   okres = 400;   break;
          case 16:   okres = 500;   break;
          default:   okres = 90;      break;
       }

       for(int32_t i= 0; i < okres; i++){   
          wartDoRejBSRR[i] = doRejBSRR;   //wartośc wyświeltana
       }
       for(int32_t i = okres; i < 500; i++){
          wartDoRejBSRR[i] = 0xFFFF0000;   //wygaszone wszystkie segmenty
       }

    Mierzyłem oscyloskopem to mam częstotliwość ok 200kHz sygnału PWM na wyjściu sterującym. Nie wiem czy jest to optymalne rozwiązanie, ale działa i nie wprowadza mi opóźnień w innych przerwaniach.

    0
  • #10 16 Wrz 2018 21:30
    BlueDraco
    Specjalista - Mikrokontrolery

    Czyli wszystko kompletnie źle.

    Po pierwsze, gdzie są rezystory ograniczające prąd segmentów?

    Po drugie, zaprogramuj timer na okres 500 i częstotliwości rzędu 1 kHz (400 Hz..2 kHz).

    Po trzecie, zamiast żenującego switcha użyj tablicy stałych:
    wypelnienie = okres[brightness];

    Po czwarte, zadeklaruj zmienną, której zapis do BSRR zaświeca potrzebne segmenty i stałą z samych jedynek, zapisywaną do BRR w celu wygaszenia.

    Zaprogramuj dwa kanały DMA do wysyłania w kółko tych dwóch danych. Zaświecaj segmenty przy końcu okresu (update), gaś przy CC1.

    0
  • #11 17 Wrz 2018 22:39
    norbis15
    Poziom 14  

    Skonfigurowałem TIM1 do sterowania jasnością. Tak jak zalecił kolega BlueDarco chciałem zapalać segmenty przy końcu okresu (update) i gasić przy CC1. Na początek chciałem wygenerować przebieg o wypełnieniu 50% wiec:
    Zgodnie z RM przy TIM1_CH1 może pracować DMA1Channel2, a do TIM1_UP DMA1Channel5:
    Sterowanie jasnością wyśw przez DMA stm32f0
    I analizując RM napisałem kod:

    Code:
      
    
    uint8_t wyswietlanyZnak = 0;// Zmienna która zawiera zakodowany znak do wyświetlenia

    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;                      /* Enable the peripheral clock of Timer x */
      TIM1->PSC = 47999;                                    /* Zegar skonfigurowane na 48Mhz, Czyli tick co 1ms */
      TIM1->ARR = 16;                                       /* 16ms okres cyklu */
      TIM1->CCR1 = 8;                                       /* w połowie okresu chcę zmianę stanu */

      RCC->AHBENR |= RCC_AHBENR_DMA1EN;                      /* Enable the peripheral clocks of DMA */
      DMA1_Channel2->CPAR = (uint32_t)&(SEG_A_GPIO_Port ->BRR);    //adres perypherium - rejestr od gaszenia diod
      DMA1_Channel2->CMAR = (uint32_t)&wygaszenie;                //adres pamięci - 0xffff
      DMA1_Channel2->CNDTR = 1;                            //1 dana
      DMA1_Channel2->CCR |= DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_1      //tryb NIE-CYKLICZNY??, ZMIENNA 16 BITOWA,
                          | DMA_CCR_PSIZE_0 | DMA_CCR_DIR;                     //NIE INKREMENTUJEMY MEMORY, Z PAMIĘCI DO RERIPHERIUM

      DMA1_Channel2->CCR |= DMA_CCR_EN;

      DMA1_Channel5->CPAR = (uint32_t)&(SEG_A_GPIO_Port ->BSRR);    //adres perypherium - rejestr do zapalania diod




      DMA1_Channel5->CMAR = (uint32_t)&wyswietlanyZnak;          //adres zmiennej z segmentami do zapalenia
      DMA1_Channel5->CNDTR = 1;                            //1 dana
      DMA1_Channel5->CCR |= DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_1      //tryb NIE-CYKLICZNY??, ZMIENNA 16 BITOWA,
                           | DMA_CCR_PSIZE_0   | DMA_CCR_DIR;    //NIE INKREMENTUJEMY MEMORY, Z PAMIĘCI DO RERIPHERIUM

      DMA1_Channel5->CCR |= DMA_CCR_EN; /* (8) */

      TIM1->DIER |= TIM_DMA_UPDATE | TIM_DMA_CC1;               /* zezwolenie na uruchamianie DMA*/
      TIM1->CR1 |= TIM_CR1_CEN;                            /* Włączamy licznik */



    Licznik instrumentuje się, Jednak mój kod nie działa tak jakbym chciał. W rejestrach DMA->ISR mam:
    Sterowanie jasnością wyśw przez DMA stm32f0
    W rejestrach TIM1:
    Sterowanie jasnością wyśw przez DMA stm32f0

    Czy ktoś widzi co jest źle ustawione?

    0
  • #12 18 Wrz 2018 07:29
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Jak dla mnie MSIZE powinno być tutaj takie samo jak PSIZE, a u Ciebie są różne. Do tego PSIZE ustawiłeś na niedozwoloną wartość.

    0