este jedna dlazdicska...

Jiri LINHART hw.jirilinhart na gmail.com
Neděle Leden 8 16:49:46 CET 2017


Nebylo by lepší v dnešní době to nechat na překladači a linkeru co s tím  
sám udělá (možná to nebude nejrychlejší a nejkratší v RAM).
Zkus se pro jistotu podívat na různé překlady možná vyjdou stejně
Pro rychlost a jednoduchost zpracování použij bytes


J.L.


Dne Sun, 08 Jan 2017 01:15:06 +0100 Jan Waclawek <konfera na efton.sk>  
napsal(a):

>> je tu nejak ticho tak pridam blbu otazku...
>>
>>
>> majme porty na procesore Atmega. Chcel by som niektore piny nadratovat
>> do boolean premennej, tak aby som po precitani dostal 0/1. Takisto by
>> som chcel zase niektore ine boolean premenne chcel nadratovat na
>> vystupne piny. Ako sa to v C spravne robi?
>
> Nijako.
>
> _Bool v C nie je typ, ktory by sa dal namapovat na bit. Presnejsie, v C
> nemoze existovat samostatny objekt (a tym ani typ, ktory by ten objekt
> popisoval), ktory by nepozostaval z jedneho alebo viacerych bytov (C99,
> 6.2.6.1#2).
>
> V C vsak existuje prostriedok na manipulaciu jednotlivych bitov, bitove
> polia (bitfields, resp. v norme sa to pise so spojovnikom bit-fields) v
> strukturach (struct). Pouzitie je trocha ine ako so samostatnou  
> premennou,
> t.j. nemozes zapisat nieco ako PORTC_1 = 1; a musis zapisat nieco ako
> PORTC.b1 = 1; - ale tipujem, ze to by Ti az tak velmi nevadilo.
>
> Zacnime vsak s tymi portami (resp. vseobecnejsie k SFR) u AVR. Tie
> samozrejme su (mozu) byt bitovo manipulovatelne, rovnako ako u '51. V
> povodnom AVR tak ako ho A&V vymysleli, je pre SFR vyhradena oblast 64
> byte, kde samotne SFR su adresovane 0x00-0x3F - to su adresy P pouzite v
> instrukciach pre SFR. Su dve instrukcie pre nastavenie/nulovanie SFR bitu
> - SBI P,b a CBI P,b (Set resp. Clear Bit in I/O) - a dve instrukcie na
> testovanie bitu a obskocenie nasledujucej instrukcie - SBIS P,b a SBIC  
> P,b
> (Skip if Bit in I/O Set resp. Cleared). Toto sa prenieslo aj do
> programovania v C s prekladacom avr-gcc - avr-gcc spociatku nevedel
> zohladnit tuto specialitu, a tak sa porty efektivne nastavovali pomocou
> makier sbi()/cbi() generujucich inline assembler - toto spominam preto,
> lebo pozostatky tych makier sa daju najst v starsich programoch ako aj v
> dokumentacii k avr-libc, a pre spatnu kompatibilitu su stale obsiahnute v
> <compat/deprecated.h>
> http://www.nongnu.org/avr-libc/user-manual/group__deprecated__items.html  
> .
>
> Sucasne vsak je cela SFR oblast namapovana aj v "unifikovanej" pamati,
> ktora u klasickych AVR obsahuje na adresach 0x00 az 0x1F registre
> procesora (uzitocnost tohoto je na velmi dlhu diskusiu a tyka sa vlastne
> len tych najmensich a najstarsich Tiny), na adresach 0x20 az 0x5F  
> klasicke
> bitovo adresovatelne SFR registre ako boli popisane hore (takze kazdy  
> taky
> register ma vlastne dve adresy, jednu v priestore SFR (od adresy 0x00) a
> druhu v unifikovanej pamati (posunutu o 0x20). Unifikovana pamat znamena,
> ze k vsetkym prostriedkom sa da pristupovat jednou sadou instrukcii v
> jednom adresnom priestore. Unifikovana pamat je prave jedna z vlastnosti
> AVR ktora bola zamerne pritomna uz od pociatku prave kvoli pouzitiu vo
> vyssich jazykoch (na cele s C), kedze tie maju notoricky problem s
> rozmanitostou pamati (prave preto vravi pan kolega Andel, ze C pre '51 je
> Keil - C pre '51 musi totiz obsahovat rozsirenia pre viacero roznych
> pamatovych oblasti, ktorych ma '51 tak zhruba 5, inak je takmer
> nepouzitelne a urcite nie efektivne pouzitelne).
>
> Klasicky bola v AVR nad SFR oblastou umiestnena SRAM (t.j. od adresy  
> 0x60).
> FLASH nebola v unifikovanej pamati (to prinasa dalsiu sadu problemov s
> konstantnymi premennymi umiestnenymi vo FLASH, toto sa vo svete avr-gcc
> prejavovalo skupinou makier a funkcii v <pgmspace.h> a s nimi spojenymi
> zvlastnostami, od urciteho casu sa to prejavuje skupinou pomenovanych
> pamatovych priestorov typu _flash) a ani EEPROM (tam sa to vsak obvykle
> ani necaka a pristupuje sa k nej dost prirodzene zvlastnymi funkciami).
> Toto sa zmenilo v xMEGA kde vznikla skutocne unifikovana pamat zahrnajuca
> vsetky prostriedky, avsak za cenu strankovania, kedze prirodzeny adresny
> priestor AVR je dost pochopitelne 16-bitovy (ta potreba vsak u FLASH  
> >64kB
> tak ci tak existuje).
>
> Vratme sa vsak k SFR. Pochopitelne, v urcitom bode prestalo 64 byte pre
> vsetky SFR stacit, a v novsich, vacsich modeloch boli dodatocne SFR
> umiestnene uz len do unifikovanej pamate, nad oblast povodnych SFR t.j.  
> od
> adresy 0x60 (a SRAM bola posunuta nad nove SFR, na adresu 0x100 a neskor
> aj vyssie). Tieto nove SFR uz teda neboli bitovo manipulovatelne, pre
> unifikovanu pamat take instrukcie nie su. (Mimochodom, aj v '51 je len
> pomerne mala cast SFR priestoru bitovo manipulovatelna, vsakze). Pre ne
> teda zmena bitu znamena precitat cely SFR do registra, zmodifikovat ten
> jeden bit, a zapisat naspat.
>
> Pisatelom v C/avr-gcc teda vznikli dve moznosti: bud si pamatat, pre  
> ktore
> SFR sa da pouzit cbi()/sbi() a pre ktore nie, alebo prosto pouzivat pre
> vsetky SFR pristup ako k normalnej pamati (to je to PORTx |= 1 << 5  
> apod.)
> aj za cenu, ze to pre tie klasicke SFR nie je optimalne. Medzicasom sa
> vsak nasiel aj dobrodinec ktory do avr-gcc doplnil optimalizaciu, ktora
> skuma, ci bitovo-manipulovana adresa je v oblasti klasickych SFR, a ak
> ano, tak pouzije cbi/sbi, co umoznilo standardizovat pristup k SFR ako k
> pamati a zachovat optimalitu. Tym padom sa stali makra cbi()/sbi()
> zastarale (deprecated) a oficialne doporuceny pristup je popisany tu:
> http://www.nongnu.org/avr-libc/user-manual/group__avr__sfr.html
>
> Ono to PORTB |= _BV(PB1); nie je omnoho zrozumitelnejsie ci citatelnejsie
> ako PORTB |= (1 << PB1), takze si to mnohi aj tak spestruju svojimi
> makrami. My vo firme napriklad mame taky postup, ze si na zaciatku
> projektu porobime makra typu
> #define SetLED1() PORTB |= (1 << 3)
> #define ClrLED1() PORTB &= ~(1 << 3)
> #define GetButton1() ((PINB & (1 << 5)) == 0)
> a podobne - je to mozno trocha tukania, ale potom zvysok programu je
> relativne dobre citatelny.
>
> Ale aby som sa po tejto obrovskej okluke vratil uplne na zaciatok, je  
> mozne
> urobit nieco taketo (http://bit.ly/2i5mMXr ):
>
> #include <stdint.h>
> #include <avr/io.h>
>
> typedef union __attribute__((packed)) {
>   uint8_t all;
>   struct __attribute__((packed)) { uint8_t nibH : 4, nibL : 4; };
>   struct __attribute__((packed)) { _Bool lsb: 1; uint8_t : 6; _Bool msb:  
> 1;
> };
>   struct __attribute__((packed)) { _Bool b0: 1, b1: 1, b2: 1, b3: 1, b4:  
> 1,
> b5: 1, b6: 1, b7: 1; };
> } bit8;
>
>
> #define SFR2BITFIELD8(sfr) (*(volatile bit8 *)(&(sfr)))
>
> #define pinC     SFR2BITFIELD8(PINC)
> #define portC    SFR2BITFIELD8(PORTC)
> #define pinF     SFR2BITFIELD8(PINF)
> #define portF    SFR2BITFIELD8(PORTF)
>
>
> int main(void) {
>   if (PINC & (1 << 4)) {
>     PORTC |= (1 << 5);
>   }
>
>   if (pinC.b4) {
>     portC.b5 = 1;
>   }
>
>
>   if (PINF & (1 << 4)) {
>     PORTF |= (1 << 5);
>   }
>   if (pinF.b4) {
>     portF.b5 = 1;
>   }
>
>   portC.b5 = !pinC.b4;
>
>   portC.b5 = ~pinC.b4;
> }
>
> z coho relevantna cast sa prelozi ako
>
>
> int main(void) {
>   if (PINC & (1 << 4)) {
>   be:	9c 99       	sbic	0x13, 4	; 19
>     PORTC |= (1 << 5);
>   c0:	ad 9a       	sbi	0x15, 5	; 21
>   }
>
>   if (pinC.b4) {
>   c2:	9c 99       	sbic	0x13, 4	; 19
>     portC.b5 = 1;
>   c4:	ad 9a       	sbi	0x15, 5	; 21
>   }
>
>
>   if (PINF & (1 << 4)) {
>   c6:	04 9b       	sbis	0x00, 4	; 0
>   c8:	05 c0       	rjmp	.+10     	; 0xd4 <main+0x16>
>     PORTF |= (1 << 5);
>   ca:	80 91 62 00 	lds	r24, 0x0062
>   ce:	80 62       	ori	r24, 0x20	; 32
>   d0:	80 93 62 00 	sts	0x0062, r24
>   }
>   if (pinF.b4) {
>   d4:	04 9b       	sbis	0x00, 4	; 0
>   d6:	05 c0       	rjmp	.+10     	; 0xe2 <main+0x24>
>     portF.b5 = 1;
>   d8:	80 91 62 00 	lds	r24, 0x0062
>   dc:	80 62       	ori	r24, 0x20	; 32
>   de:	80 93 62 00 	sts	0x0062, r24
>   }
>
>   portC.b5 = !pinC.b4;
>   e2:	83 b3       	in	r24, 0x13	; 19
>   e4:	82 95       	swap	r24
>   e6:	8f 70       	andi	r24, 0x0F	; 15
>   e8:	80 95       	com	r24
>   ea:	81 70       	andi	r24, 0x01	; 1
>   ec:	82 95       	swap	r24
>   ee:	88 0f       	add	r24, r24
>   f0:	80 7e       	andi	r24, 0xE0	; 224
>   f2:	95 b3       	in	r25, 0x15	; 21
>   f4:	9f 7d       	andi	r25, 0xDF	; 223
>   f6:	98 2b       	or	r25, r24
>   f8:	95 bb       	out	0x15, r25	; 21
>
>   portC.b5 = ~pinC.b4;
>   fa:	83 b3       	in	r24, 0x13	; 19
>   fc:	ad 9a       	sbi	0x15, 5	; 21
>
>
> (domaca uloha: vysvetlit preklad posledneho riadku)
>
> wek
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list


-- 
Vytvořeno poštovní aplikací Opery: http://www.opera.com/mail/


Další informace o konferenci Hw-list