Fórum témák

» Több friss téma
Fórum » ARM - Miértek hogyanok
 
Témaindító: gtk, idő: Jún 26, 2007
Lapozás: OK   139 / 176
(#) benjami válasza don_peter hozzászólására (») Júl 11, 2019 / 1
 
Itt van mintának az általam írt stm32 lcd driver. Megkeresed a kérdéses kijelzőhöz legjobban hasonlító drivert (pl. ili9325) és csak azt kell átszabni az általad használt kijelzőhöz. Ehhez mintának meg fel lehet használni a fenti arduino verziót.
Az FSMC úgy állítja az IO portokat, hogy mindössze egyetlen memória írás vagy olvasás kell az adat küldéséhez ill. fogadásához. Nem kell külön billegtetni a CS, RD, WR, RS lábakat, ezt hardverből megoldja. Az RS (command/data) lábat az egyik címbitre kell kötni, így a memóriacím fogja eldönteni, hogy parancsot vagy adatot küldesz a kijelzőnek. Az FSMC inicializálást a cube amúgy a "stm32f4xx_hal_msp.c" -be teszi.
(#) don_peter válasza benjami hozzászólására (») Júl 11, 2019 /
 
  1. #define LCD_BASE        ((u32)(0x6C000000 | 0x000007FE))
  2. #define LCD             ((LCD_TypeDef *) LCD_BASE)

Még ezzel a résszel van gondom, én A10-et választottam, mivel a próba panelomon ez van bekötve az LCD RS vezérlésére, ez a G0-ás PIN.
Stm32CubeMX-ben NOR1/SRAM/LCD1-et választottam és NE4-et.

Elvileg jól állítom a memória elérést még sem döccen be a kijelző.
Valamit rosszul csinálhatok a bázis cím megadásánál?

Bővebben: Link
A hozzászólás módosítva: Júl 11, 2019
(#) benjami válasza don_peter hozzászólására (») Júl 11, 2019 / 1
 
Az én programomban így lenne ezekkel a paraméterekkel.
A headerben a konfiguráció:
  1. /* Memoria cimek hozzárendelése, tipikus értékek:
  2.   - Bank1 (NE1) 0x60000000
  3.   - Bank2 (NE2) 0x64000000
  4.   - Bank3 (NE3) 0x68000000
  5.   - Bank4 (NE4) 0x6C000000
  6.   - REGSELECT_BIT: ha pl. A18 lábra van kötve, akkor -> 18 */
  7. #define LCD_ADDR_BASE     0x6C000000
  8. #define LCD_REGSELECT_BIT 10


Ekkor C forrásban így alakulna:
  1. #define LCD_ADDR_DATA  (LCD_ADDR_BASE + (1 << LCD_REGSELECT_BIT))


Így a parancs a 0x6C000000 címen, az adat pedig a 0x6C000400 címen lenne elérhető.
(#) don_peter válasza benjami hozzászólására (») Júl 11, 2019 /
 
Akkor ez stimt, így csinálom én is. No akkor máshol lesz a gond.
(#) benjami válasza don_peter hozzászólására (») Júl 11, 2019 /
 
Az mondjuk fura, hogy a bázis címedbe (LCD_BASE) miért az adat (RS = 1) elérése került.
(#) don_peter válasza benjami hozzászólására (») Júl 11, 2019 /
 
Miért minek kell oda kerülnie?

Ilyen fejlesztőm van: Bővebben: Link
A hozzászólás módosítva: Júl 11, 2019
(#) benjami válasza don_peter hozzászólására (») Júl 11, 2019 /
 
Számomra az lenne a logikus, ha a bázis cím lenne a 0x6C000000 (erre a címre a parancsokat kell írni), az LCD_ADDR_DATA -ba pedig a 0x6C0007FE (ide kell írni a parancsok paramétereit és a pixeladatokat).
(#) don_peter hozzászólása Júl 11, 2019 /
 
Rá tudna valaki pillantani?
Csatoltam a teljes projektet.
STM32F407GZT6-os kontrollert használok és egy OTM8009A típusú csippel szerelt, 800x480-as TFT LCD kijelzőt szeretnél be izzítani, ha sikerül.
Mostanra eljutottam odáig, hogy nem látom a fától az erdőt.

Ami még fontos lehet az a kapcsolási rajz amelyet csatoltam szintén.
Atollic TrueStudio for STM32-t használok és C-ben kódolgatok.

Előre is köszi a belefektetett energiát bárki is szán rá néhány percet..
A hozzászólás módosítva: Júl 11, 2019
(#) don_peter válasza don_peter hozzászólására (») Júl 12, 2019 /
 
Úgy fest találtam egy olyat is ami hajlandó működni is.
Abból szerintem tudok kicsit jobban építkezni és esetleg megvizsgálni miért nem megy ez a másik. Szóval köszi srácok, de lehet hogy tovább tudok lépni végre.
(#) don_peter hozzászólása Júl 12, 2019 /
 
Srácok, esetleg nincs valakinek egy jó kis BMP vagy JPG esetleg PNG kirajzoló progija TFT kijelzőre?
Előre is köszi.
(#) don_peter válasza don_peter hozzászólására (») Júl 12, 2019 /
 
Megírtam.. Köszi..
(#) don_peter hozzászólása Júl 13, 2019 /
 
Srácok ismét kérnék egy kis segítséget.
Megszakításban szeretném kezelni az UART-on történő adatok fogadását.
Így néz ki most a megszakításom:
  1. void USART1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN USART1_IRQn 0 */
  4.  
  5.   /* USER CODE END USART1_IRQn 0 */
  6.   HAL_UART_IRQHandler(&huart1);
  7.   /* USER CODE BEGIN USART1_IRQn 1 */
  8.   RxFlag = HAL_UART_Receive_IT(&huart1, RxBuffer, sizeof(RxBuffer));
  9.   /* USER CODE END USART1_IRQn 1 */
  10. }
Az stm32f4xx_it.c fájl elején létrehozom a változót, amelyet egy flag-ként használok, ha érkezik adat, akkor tudjak róla. Ezt emígy:
  1. extern unsigned char RxBuffer[140] = {0};
  2. volatile unsigned char RxFlag = 0;
Mind kettő esetében elérhetetlen főprogramban a változó.
Mint a buffer mint pedig a flag is.

A kérdés, hogy tudnék olyan globális változót létrehozni, amelyet a megszakításban és a főprogramban is elérhetek?
A hozzászólás módosítva: Júl 13, 2019
(#) kapu48 válasza don_peter hozzászólására (») Júl 13, 2019 / 1
 
Az stm32f4xx_it.h-ba teszed az extern módosítást:
extern unsigned char RxBuffer[140] ;
extern volatile unsigned char RxFlag;

Az stm32f4xx_it.c-ben létrehozod:
unsigned char RxBuffer[140] = {0};
volatile unsigned char RxFlag = 0;

És beszúrod, ahol használni akarod:
#include stm32f4xx_it.h
A hozzászólás módosítva: Júl 13, 2019
(#) don_peter válasza kapu48 hozzászólására (») Júl 13, 2019 /
 
Köszi, így most jó lesz a változó..
(#) don_peter hozzászólása Júl 14, 2019 /
 
Uraim ismét elakadtam.
STM32-őn még soha nem foglalkoztam sima USART/UART-al, és nem is igen értem, hogy miért nincsenek olyan rutinok, amelyekkel könnyedén figyelni tudnám, hogy beérkezett a küldött összes adat. Mondom is mi a bánatom, lehet csak én közelítem meg rosszul a dolgot.

Tehát van egy csomagom, aminek (elvileg) tudom a hosszát, ezt a csomagot megszakításból szeretném venni, ez megy is. De magát a csomagot, csak a főprogramban akarom kiértékelni és csak is akkor, ha az teljes egészében megérkezett a csomag, hisz csak akkor van értelme.

Próbálkoztam a HAL_UART_GetState() lekérdezésével, de nem hozott eredményt mivel a megszakítás olykor magától is lefut, persze nem csinál semmit, de a vissza kapott érték megegyezik azzal, amikor kap adatot.
Próbálkoztam ezen kívül saját változókkal, de nem megbízható ez a megoldás sem, mert a megszakítás olykor magától is lefut.
Továbbá ugyan az a megszakítás fut le, ha küldök ki adatot, bár ezt talán én is ki tudom kapcsolni, de most ez is játszik.

Hogyan tudnék egy olyan kis feltételt írni akár megszakításban, akár főprogramban, amely csak akkor teljesülne amikor, beérkezett az összes adat és csak is kizárólag a kapott adatokat figyelné? Akár egy kis példát is szívesen vennék.

Előre is köszi a segítséget.

STM32F407VG, Atollic TrueStudio
(#) Topi válasza don_peter hozzászólására (») Júl 14, 2019 / 2
 
Ha nem DMA-s, akkor
RXNE interrupt + puffer + beérkezett byte számláló + állapotgép.

Vagy az RX interruptba teszed az állapotgépet, vagy az RXNE + TC + TXE interruptok csak pufferbe töltés célokat szolgálnak, majd később dolgozod fel.
Én azt szoktam csinálni, hogy pl. vagy egy ABCD_ReadPacket() függvény, amit a taskban hívok meg, és ha nincs egész csomag, akkor NULL-al tér vissza, de magának ennek a függvénynek a meghívása működteti a csomagfeldolgozó állapotgépet.

Írok egy mintakódot dummy struktúrával, dummy 0x80+0x7F opkód maszkkal, hogy érthető legyen mire gondolok (nem biztos, hogy syntax helyes, inkább pszeudokódként olvasd):
  1. typedef struct {
  2.   unsigned char op_code;
  3.   unsigned char pkt_len;
  4.   unsigned char data[16];
  5. } t_csomag;
  6.  
  7.  
  8. enum {S_NONE = 0, S_WAIT_FOR_OPCODE, S_WAIT_FOR_LEN, S_WAIT_FOR_DATA, S_XOR} s_read_packet;
  9. unsigned char bcount = 0;
  10. t_csomag temp_csomag;
  11.  
  12. t_csomag ABCD_ReadPacket() {
  13.         unsigned char d = USART_ReadDataByteBlabla();
  14.        
  15.         if(s_read_packet == S_NONE) {
  16.                 //init
  17.                 s_read_packet = S_WAIT_FOR_OPCODE;
  18.         } else
  19.         if(s_read_packet == S_WAIT_FOR_OPCODE) {
  20.                 if(d & 0x80) {
  21.                         //felso bitje 1 tehat opcode
  22.                         temp_csomag.op_code = d;
  23.                         s_read_packet = S_WAIT_FOR_LEN;
  24.                 }
  25.         } else
  26.         if(s_read_packet == S_WAIT_FOR_LEN) {
  27.                 //most packet len-t kaptunk
  28.                 temp_csomag.pkt_len = d;
  29.                 bcount = 0;
  30.                 s_read_packet = S_WAIT_FOR_DATA;
  31.         } else
  32.         if(s_read_packet == S_WAIT_FOR_DATA) {
  33.                 temp_csomag[bcount++] = d; //eltesszuk az adatot
  34.                 if(bcount == temp_csomag.pkt_len) {
  35.                         //utolso bajt volt, megyunk XOR-olni majd a kovetkezo berkezeskor
  36.                         s_read_packet = S_XOR;
  37.                 }
  38.         } else
  39.         if(s_read_packet == S_XOR) {
  40.                 //checksum ellenorzes
  41.                 unsigned char xor_temp;
  42.                 xor_temp = d;
  43.                 for(unsigned char i=0;i<temp_csomag.pkt_len;i++) {
  44.                         xor_temp ^= temp_csomag.data[i];
  45.                 }
  46.                
  47.                 //opcodera varunk majd, akar jo akar nem
  48.                 s_read_packet = S_WAIT_FOR_OPCODE;
  49.                 if(xor_temp == 0) {
  50.                         //mondjuk a dummy packet akkor jo ha bytejai xorja 0
  51.                         //visszateres valos csomaggal
  52.                         return &temp_csomag;
  53.                 }
  54.         }
  55.        
  56.         return NULL;
  57. }
  58.  
  59. void DummyCsomagReadTask() {
  60.         t_csomag *msg;
  61.        
  62.         msg = ABCD_ReadPacket();
  63.         if(!msg) return; //nincs itt semmi latnivalo, nincs meg kesz csomag
  64.        
  65.         //kaptunk csomagot
  66.         switch(msg.op_code) {
  67.                 case OPC_VALAMI:
  68.                  //TODO
  69.                 break;
  70.         }
  71. }
  72.  
  73. ...
  74.  
  75. while(1) {
  76.         ...
  77.         ...
  78.         DummyCsomagReadTask();
  79.         ...    
  80. }
(#) Peppe válasza don_peter hozzászólására (») Júl 14, 2019 /
 
Soros port esetén tudsz megszakítást kérni, hogy adott beérkezett bájt után adjon csak IT-t neked. Amikor az IT HAL függvényt konfigolod. akkor nem 1 bájtot adsz meg hanem x bájtra.
(#) don_peter válasza Topi hozzászólására (») Júl 14, 2019 /
 
Uhh ez szép, de mint jeleztem is még soha nem csináltam ilyesmit STM32-őn.
Illetve csaj külön az UART-ot nem, mert CDC-t igen, de az merőben más volt.

Mutatom hogy miért is akaszt le az általad felvázolt megoldás.
Mint írtam is megszakításban szeretném kezelni a teljes csomag beékezését és csak akkor érdekel a főprogramban a csomag, ha az maradéktalanul beérkezett.
Ehhez csak egy feltétel kellene nekem, mondjuk egy flag-el, amely ha bebillen, akkor a csomag beérkezett és feldolgozható.

Jelenleg itt tartok:
Megszakítás kiszolgálása:
  1. void USART1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN USART1_IRQn 0 */
  4.  
  5.   /* USER CODE END USART1_IRQn 0 */
  6.   HAL_UART_IRQHandler(&huart1);
  7.   /* USER CODE BEGIN USART1_IRQn 1 */
  8.   HAL_UART_Receive_IT(&huart1, RxBuffer, 1);
  9.   // Ezt csak tesztelgetem, hogy mit is mutat, hasznos e esetleg
  10.   RxFlagCount = HAL_UART_GetState(&huart1);
  11.  
  12.   /* USER CODE END USART1_IRQn 1 */
  13. }

Main()
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);    // Aktíváljuk Rx megszakítást
  2. // És ide jöhetne a főprogram.
  3. while(1){
  4.     if(bejött_a_teljes_csomag == true){
  5.         // Feldolgozzuk az adatokat.
  6.     }
  7.     // Program többi része...
  8. }

Itt látszik is, hogy elvileg a __HAL_UART_ENABLE_IT() rutin, elintézi nekem megszakításban az összes adat fogadását. Igen ám, csak ha végez nem szól, hogy heeee, kész vagyok és nem jön több adat, dolgozhatsz...
Nah ez az én bánatom.

Az általad mutatott példa pedig feltételezi, hogy minden fogadott byte-ot én kezelek és számolok, gondolom.
Vagy ennél az esetnél másként kell a megszakítást kezelnem?
Teszem azt csak a megszakítást kérelmet használom és kihagyom a __HAL_UART_ENABLE_IT() rutint és más módon kellene vennem az adatokat? Csak mert HAL-t használok és ott nem tudom külön az érkezett byte-okat venni. Szóval el vagyok kicsit veszve..
(#) don_peter válasza Peppe hozzászólására (») Júl 14, 2019 /
 
Hol tudom ezt beállítani? Vagy mit keressek, mert egyelőre ilyen beállítási opciót nem látok sehol. STM32CubeMx-et használok, de ott sem találtam ilyen beállítási lehetőséget.
Valahol el van ez rejtve?
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 /
 
Itt végig nézheted: Tutorial CubeMX - 7- USART RxTx Interrupts STM32F4 Discovery
Bővebben: Link

Csak megjegyzem keresni kel! Ez volt az első találat!
A hozzászólás módosítva: Júl 14, 2019
(#) don_peter válasza kapu48 hozzászólására (») Júl 14, 2019 /
 
Köszi, ezzel kezdtem 3szor néztem végig már jóval korábban, de sajna ez nem jó nekem.
A srác ugyan megszakításban kezeli az adatokat, de sajna ahol fogadja ott küldi is egyből.
Nekem megszakításban kell fogadni a csomagot, de csak majd főprogramban kell értelmeznem.
Adat is csak akkor, jön ha főprogramból kérem, és így tovább..
A hozzászólás módosítva: Júl 14, 2019
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 / 1
 
Már ne haragudjál meg! De ebből már elindulhatsz!
(Nem ártana, ha kicsit megpróbálsz gondolkozni! Ne félj nem fog fájni.)


  1. Visszakapod az: HAL_OK-ot, ezt figyeled a megszakításban, és akkor csinálod ami akarsz.
  2. HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
  3. /**
  4.   * @brief  HAL Status structures definition  
  5.   */  
  6. typedef enum
  7. {
  8.   HAL_OK       = 0x00U,     <<<
  9.   HAL_ERROR    = 0x01U,
  10.   HAL_BUSY     = 0x02U,
  11.   HAL_TIMEOUT  = 0x03U
  12. } HAL_StatusTypeDef;
A hozzászólás módosítva: Júl 14, 2019
(#) don_peter válasza kapu48 hozzászólására (») Júl 14, 2019 /
 
Nem haragszom, de unszimpatikus az ilyen felesleges bejegyzés.

Tehát megy a megszakítás és mennek az adatok, a linkelt videó alapján, működik a kommunikáció. De nem csak arra van szükségem, hogy működjön, használni is akarom, ehhez pedig kellene valamiképpen figyelnem, hogy sikeresen beérkezett e a várt csomag.

No ebbe kértem az elméleti vagy akár példa kóddal való segítséget.
Mi nem világos abból amit leírtam fentebb?
Elindultam és működik, működik és működik.
De az kevés. Meg tudom oldani béna módon, hogy minden ciklusban végig futok a tömbön majd, ha meg van az adat ellenőrzöm és ha oké, akkor feldolgozom, de ez sok idő és csúnya megoldás.
Szebben akarom megoldani és lehetőleg kevés lépésből, ezért kérdeztem hogy milyen megoldások vannak rá, aki ebben jártas annak 10 másodperc, aki kezdő mint én, annak egy szép és jó megoldás napok. Ennyi az egész.

"Googel a barátod", nem értem egyébként, hogy sokan azt hiszik, hogy nem ez az első dolog aminek a kezdő nekiesik, elmondom: De ez az első és túl vagyok a keresgélésen.
Amúgy meg ha minden a google-ra bizgatnánk nem kellenének az ilyen fórumok sem, ebben remélem egyet értünk. Szóval egyelőre még keresem a jó megoldást.

Túl vagyok a HAL_OK figyelésén.
Mint írtam is korábban van úgy, hogy magától is lefut a megszakítás és ilyenkor HAL_OK-al tér vissza, ami nekem nem jó.
A hozzászólás módosítva: Júl 14, 2019
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 / 1
 
  1. Megszakításban:
  2. if(HAL_UART_Receive_IT(&huart1, pData, 5) == HAL_OK){
  3.  // megjött az 5 karakter, esetleg ellenőrzöd?
  4.  ...
  5. }


Ez lenne a lényeg!
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 / 1
 
strcmp és strncmp – két string összehasonlítása:
Bővebben: Link
(#) vargham válasza don_peter hozzászólására (») Júl 14, 2019 / 1
 
A lényeg az, hogy a HAL receive IT és receive DMA függvény is kér egy hossz paramétert. De te ezt nem tudod, mert változó hosszúságúak a csomagjaid. A HAL viszont honnan a fenéből tudná, hogy bejött egy csomagod? Az UART alapból nem csomagalapú kommunikációs csatorna, mint mondjuk a CAN bus. Tehát akárhány bájtod érkezhet, akármilyen időzítéssel. Akár sok-sok szünettel is a bájtok között. Ezért szokás valami header-t használni, amiből felismeri a te szoftvered, hogy hol kezdődik a te csomagod, a header-ben benne van, hogy milyen hosszú, CRC, miegymás. De mindezt nem a megszakításkezelőben fogod csinálni, mert onnan mielőbb ki kell lépni.

Neked az Rx idle megszakításra van szükséged. Sajnos a HAL-ból hiányzik ennek a kezelése, de te belerakhatod magadnak. A lényege az, hogy elindtasz egy UART receive DMA-t, és figyelmen kívül hagyod a DMA completed IT-t. Helyette az Rx idle-re ugrasz. Ha nem túl idióta módon, például sok köztes szünettel, érkezik az adat a küldőtől, akkor az IT jó eséllyel akkor jelez, amikor pont egy egész csomag érkezett. A megszakításban át is másolhatod a DMA bufferből a feldolgozás helyére, vagy ébreszthetsz egy magas prioritású RTOS taskot, és akkor elég a csomag elejét meg végét jelző pointert átadnod. Ehhez természetesen az kell, hogy a DMA receive buffer akkora legyen, hogy a kiolvasásig még ne íródjon felül a következő csomaggal.

Bővebben: Link
(#) don_peter válasza kapu48 hozzászólására (») Júl 14, 2019 /
 
Köszi, működik, de random mód érkezik adat amit nem értek egyelőre.
De azt hiszem akkor marad ez a megoldás és majd ellenőrzöm az adatokat is.
Köszi.
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 /
 
Mi küldi az adatokat?

A PC terminálok küldenek kocsi vissza, soremelés parancsokat.
A string végére tesz pluszban /0-át. Ezeket mind lekel kezelni, és a végén törölni a puffert.
Mert ha marad benne valami, akkor vannak a hibás működések.
(#) don_peter válasza kapu48 hozzászólására (») Júl 14, 2019 /
 
Terminállal tesztelem, de kikapcsolok mindent csak az adatot küldöm.
Nem értem a + random adatot. Olyan mint ha tényleg valami lezáró adat lenne, de olykor magától is megszakít.
(#) kapu48 válasza don_peter hozzászólására (») Júl 14, 2019 /
 
Vagy ha kicsi a puffer, mert a példánál maradva, az 5 karakternek nem elég az 5 Byte-os buffer.
Következő: »»   139 / 176
Bejelentkezés

Belépés

Hirdetés
Lapoda.hu     XDT.hu     HEStore.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem