ATTINY 48 ukazatel na port, problém s PROGMEM – Mikrokontroléry – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

ATTINY 48 ukazatel na port, problém s PROGMEM – Mikrokontroléry – Fórum – Programujte.comATTINY 48 ukazatel na port, problém s PROGMEM – Mikrokontroléry – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
29. 11. 2018   #1
-
0
-

   

#include <avr/io.h>
#include "avr/pgmspace.h"

uint8_t i;

typedef struct
{
	volatile uint8_t *relPort;
	uint8_t relMaska;
	volatile uint8_t *ledPort;
	uint8_t ledMaska;
} OUTPUT;

//const PROGMEM
 OUTPUT outputs[7] = {
	{ &PORTA, 1<<PORTA2, &PORTB, 1<<PORTB0 },
	{ &PORTD, 1<<PORTD4, &PORTB, 1<<PORTB1 },
	{ &PORTD, 1<<PORTD3, &PORTB, 1<<PORTB2 },
	{ &PORTA, 1<<PORTA0, &PORTD, 1<<PORTD7 },
	{ &PORTD, 1<<PORTD2, &PORTD, 1<<PORTD6 },
	{ &PORTD, 1<<PORTD1, &PORTD, 1<<PORTD5 },
	{ &PORTD, 1<<PORTD0, &PORTB, 1<<PORTB7 }
};


int main(void)
{
    //inicializace portu
    DDRA = ~(1<<DDA1);	//PA1 je analogovy vstup
    DDRB = ~(1<<DDB4);	//PB4 jako vstup MISO
    DDRC = 1<<DDC7;		//PC7 jediny nevyuzity pin, ostatni jsou vstupy
    DDRD = 0xFF;		//cely port jako vystupy

	for (i=0; i<7; i++)
	{
		*(outputs[i].ledPort) |= outputs[i].ledMaska;
	}

	while (1) 
    {
		
    }
}


Výše uvedený kód funguje - rozsvítí LED na požadovaném portu. Problémy nastanou když chci umístit pole
OUTPUT outputs[7] do paměti programu (v kódu je to vykomentováno). Jak toto pole struktur dostanu do paměti programu aby byl kód funkční?

Ještě jsem zkusil

#include <avr/io.h>
#include "avr/pgmspace.h"

uint8_t i;

typedef struct
{
	volatile uint8_t *relPort;
	uint8_t relMaska;
	volatile uint8_t *ledPort;
	uint8_t ledMaska;
} OUTPUT;

const PROGMEM OUTPUT outputs[7] = {
	{ &PORTA, 1<<PORTA2, &PORTB, 1<<PORTB0 },
	{ &PORTD, 1<<PORTD4, &PORTB, 1<<PORTB1 },
	{ &PORTD, 1<<PORTD3, &PORTB, 1<<PORTB2 },
	{ &PORTA, 1<<PORTA0, &PORTD, 1<<PORTD7 },
	{ &PORTD, 1<<PORTD2, &PORTD, 1<<PORTD6 },
	{ &PORTD, 1<<PORTD1, &PORTD, 1<<PORTD5 },
	{ &PORTD, 1<<PORTD0, &PORTB, 1<<PORTB7 }
};


int main(void)
{
    //inicializace portu
    DDRA = ~(1<<DDA1);	//PA1 je analogovy vstup
    DDRB = ~(1<<DDB4);	//PB4 jako vstup MISO
    DDRC = 1<<DDC7;		//PC7 jediny nevyuzity pin, ostatni jsou vstupy
    DDRD = 0xFF;		//cely port jako vystupy

    i=0;
    *(outputs[i].ledPort) |= outputs[i].ledMaska;

    i=1;
    *(outputs[i].ledPort) |= outputs[i].ledMaska;

    while (1) 
    {
		
    }
}


funguje také.

Prostě ty jednotlivé LED potřebuji obsloužit v cyklu.

hu

Nahlásit jako SPAM
IP: 2001:af0:ffe4:85f4:3c1f:6294:fc27:1f95...–
MilanL+1
Grafoman
30. 11. 2018   #2
-
0
-
Nahlásit jako SPAM
IP: 91.139.9.–
30. 11. 2018   #3
-
0
-

Toto je jiný případ. Kód se zkompiluje bez chyb, bez jakéhokoliv upozornění. Ještě horší je situace o fakt, že kód v simulátoru funguje očekávaným způsobem (teď jsem to zkusil), ale v procesoru nikoliv, bez ohledu na to, zda je připojen emulátor a krokuji nebo zda je emulátor zcela odpojen a program běží bez zásahů z venčí.

Navrhované pořadí modifikátorů způsobí nefunkčnost kódu na simulátoru, stav PORTx zůstává nezměněný. Přesně takto se chová původní program na procesoru. Tonoucí se stébla chytá a tak večer s reálným HW vyzkouším jiné pořadí modifikátorů. Snad bude platit, že HW se chová jinak než simulátor i v tomto případu.

const je ve spojení s PROGMEM povinné, bez něj překladač hlásí chybu (pochopitelně). Modifikovat obsah paměti programu "at runtime" se považuje za nepřípustné. Umístění do paměti programu chci hlavně proto, že se tato HW konfigurace bez zásahu do DPS nedá změnit. Toto pole říká, na jaký port a bit portu je "zadrátováno" které relé, která LED.

Cílem tohoto přístupu je rozsvícení a zhasnutí kterékoliv LED pomocí navenek jednoduchých maker (použít LED_ON() je při psaní programu přátelštějští). Totéž platí pro ovládání relé.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
KIIV
~ Moderátor
+43
God of flame
30. 11. 2018   #4
-
0
-

Nikde nevidim nacteni dat z tech PROGMEM adres (a az pak je muzes pouzit).

Co delas ted je to, ze mas adresu do FLASH, ale pouzijes ji pro nacteni dat z RAM.

Nahlásit jako SPAM
IP: 185.163.40.–
Program vždy dělá to co naprogramujete, ne to co chcete...
MilanL+1
Grafoman
30. 11. 2018   #5
-
0
-
Nahlásit jako SPAM
IP: 91.139.9.–
jerry
~ Anonymní uživatel
512 příspěvků
30. 11. 2018   #6
-
0
-

#1 hlucheucho
obávám se že ti to možná nepude, jde o to, že každý překladač je individuální a pokud nemáš znalosti assembleru tak to muže dělat problémy, viděl si jak se to přeložilo ? dal sis výpis kodu v assembleru ? hoď sem ten kousek v assembleru ... ať vidíme jak to vypadá a taky de o to že paměť v tak malý m procesoru je malá takže ... abys to nepřešvih...

Nahlásit jako SPAM
IP: 2a00:1028:83be:235a:7c9a:7cd9:106d:90be...–
KIIV
~ Moderátor
+43
God of flame
30. 11. 2018   #7
-
0
-

V cistem C by to teoreticky mohlo jet za pouziti __flash, se pak k zakladnimu pristupu pouziva instrukce LPM (avr-gcc od verze 4.6). Ale netusim, jak to zvladne struktury. A v C++ to vubec neexistuje, tam jedine pgm_read_* makra.

https://gcc.gnu.org/onlinedocs/gcc-4.7.4/gcc/Named-Address-Spaces.html#Named-Address-Spaces

Krom toho by se adresy mohly vejit i do jednoho bajtu. Takze by se cela struktura mohla nacist jednim pgm_read_dword(). Ale pro zmenu by se tam saskovalo s pretypovanim.

Nahlásit jako SPAM
IP: 185.163.40.–
Program vždy dělá to co naprogramujete, ne to co chcete...
30. 11. 2018   #8
-
0
-
Nahlásit jako SPAM
IP: 195.178.67.–
30. 11. 2018   #9
-
0
-

#4 KIIV

V tom asi bude kámen úrazu. Struktura jde zkopírovat pomocí memcpy_P funkce. 

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Řešení
30. 11. 2018   #10
-
0
-
Vyřešeno Nejlepší odpověď

 Zkopírovat celou strukturu a pak s ní pracovat:

#include <avr/io.h>
#include "avr/pgmspace.h"

uint8_t i;

typedef struct
{
	volatile uint8_t *relPort;
	uint8_t relMaska;
	volatile uint8_t *ledPort;
	uint8_t ledMaska;
} OUTPUT;

const OUTPUT outputs[7] PROGMEM = {
	{ &PORTA, 1<<PORTA2, &PORTB, 1<<PORTB0 },
	{ &PORTD, 1<<PORTD4, &PORTB, 1<<PORTB1 },
	{ &PORTD, 1<<PORTD3, &PORTB, 1<<PORTB2 },
	{ &PORTA, 1<<PORTA0, &PORTD, 1<<PORTD7 },
	{ &PORTD, 1<<PORTD2, &PORTD, 1<<PORTD6 },
	{ &PORTD, 1<<PORTD1, &PORTD, 1<<PORTD5 },
	{ &PORTD, 1<<PORTD0, &PORTB, 1<<PORTB7 }
};

OUTPUT out;

int main(void)
{
	//inicializace portu
	DDRA = ~(1<<DDA1);	//PA1 je analogovy vstup
	DDRB = ~(1<<DDB4);	//PB4 jako vstup MISO
	DDRC = 1<<DDC7;		//PC7 jediny nevyuzity pin, ostatni jsou vstupy
	DDRD = 0xFF;		//cely port jako vystupy

	for (i=0; i<7; i++)
	{
		memcpy_P(&out, &outputs[i], sizeof(OUTPUT));
		*(out.ledPort) |= out.ledMaska;
	}

	while (1)
	{
		
	}
}

hu

Edit: na HW to otestuji až večer.

Nahlásit jako SPAM
IP: 195.178.67.–
MilanL+1
Grafoman
30. 11. 2018   #11
-
0
-

#6 jerry
no data v progmem by spíš měli kod šetřit ne? by tam měli být tak jako tak, jen se při tom normálním použití kopírujou do ram při startu, nebo to chápu špatně? ATtiny 48 má myslím paměti dost na jednoduchý prográmek 4K/256/64

Nahlásit jako SPAM
IP: 91.139.9.–
KIIV
~ Moderátor
+43
God of flame
30. 11. 2018   #12
-
0
-

#11 MilanL
progmem setri hlavne RAM. Jelikoz vetsina AVR nema pristup k FLASH bez specialni instrukce, tak se vsechny konstanty zkopiruji do RAM, kde to jen zabira misto (a hlavne retezcove konstanty byvaji nejvetsi). Takze mas ty data nejen ve FLASH, ale jeste mas i kopii v RAM. Coz zaroven zabere nejaky cas pri startu programu, nez se to vsechno zkopiruje.

Ale mas pravdu, ze pro tohle mnozstvi dat bych to resil asi az bude zabrana RAM tak z vic jak poloviny.

Nebo to zkompaktnil. Dva bity na Port, tri bity na pin. Dalo by se to narvat do dvou bajtu za cenu trosku slozitejsiho dekodovani.

Nahlásit jako SPAM
IP: 185.163.40.–
Program vždy dělá to co naprogramujete, ne to co chcete...
30. 11. 2018   #13
-
0
-

#11 MilanL
Ano. Pokud to je  

OUTPUT outputs[7] = {
	{ &PORTA, 1<<PORTA2, &PORTB, 1<<PORTB0 },
	{ &PORTD, 1<<PORTD4, &PORTB, 1<<PORTB1 },
	{ &PORTD, 1<<PORTD3, &PORTB, 1<<PORTB2 },
	{ &PORTA, 1<<PORTA0, &PORTD, 1<<PORTD7 },
	{ &PORTD, 1<<PORTD2, &PORTD, 1<<PORTD6 },
	{ &PORTD, 1<<PORTD1, &PORTD, 1<<PORTD5 },
	{ &PORTD, 1<<PORTD0, &PORTB, 1<<PORTB7 }
};

pak takové pole struktur existuje v paměti kódu spolu s mechanismem jeho kopírování do RAM pro inicializaci proměnné outputs. RAM není nazbyt a tak se doporučuje konstanty umístit do paměti programu. Uvedené pole struktur představuje 28 B. Při 256 B SRAM je to citelná ztráta. Zvlášť pak v cílové aplikaci, kde je obdobných konfigurací HW více a ke všemu je RAM využitá natolik, že jsem musel použít SPI SRAM.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 5 hostů

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý