Re: EEPROM, C++ a řetěžování operátorů

Pavel Hudeček edizon na seznam.cz
Sobota Květen 27 22:42:57 CEST 2023


Žádná odpověď nepřišla, tak jsem zatím přetěžoval operátor << v rámci 
pokusů na téma jestli by v AVR nešlo používat sériák C++ stylem cout << ...
A zdá se, že to jde a docela snadno. Výsledek sice sežral velkou část 
flashky v ATtiny416, ale vzhledem k tomu, že cílem je to použít v 
AVR64DD32, kde 64 je velikost flashky a 32 má blízko k ceně v Kč...
A předpokládám, že na ARMech to taky nebude problém.

Kdo chce prozkoumat, v příloze je zdroják.
Má to několik nastavení, třeba zda automaticky oddělovat čísla, nebo 
jestli char má brát jako písmenko nebo číslo.

Všechny řádky v tom while jsou funkční, ale při spuštění na 
ATtiny416-Xnano se všechny najednou nevejdou. Ten s floatama vyžaduje 
zakomentování všech ostatních:-)

PH

Dne 26.05.2023 v 14:05 Pavel Hudeček napsal(a):
> Dobrý den všem,
>
> jsem poměrně zmlsanej používáním EEPROM v CodeVisionu. Typické 
> zpracování naměřených dat vypadá cca takto:
>
> for (n=0; n<ADC_chanCnt; n++) {
>     adData[n] = (float)(adc_data[n] + eCalOffs[n]) * eCalMult[n];
> }
>
> Můžou se tam ale vyskytnout i složitější výpočty, třeba po 
> if(n==ADC_idxTemp).
>
> Když ale totéž chci udělat v Atmel Studiu, což je zas jinak mnohem 
> lepší IDE než CodeVision, navíc je zdarma a bez komplikací po vypršení 
> doby podpory k online licenci, vzniknou z toho hrůzy obsahující funkce 
> jako  eeprom_read_float(&eCalOffs + n), případně se třeba u int musí 
> ten pointer přetypovávat, aby ho sežrala funkce eeprom_read_word a 
> když jde o zápis, tak přetypovávat i vstupní hodnotu. Prostě fakt 
> otravný.
>
> Tak jsem si řekl, že tohle by přece šlo napsat v C++. Udělat si na to 
> nějakej class, jen to bude jednou hodně práce.
>
> Narazil jsem na problém, že nevím, jak udělat přetížení operátorů pro 
> všech 8 kombinací RAM a EEPROM na vstupech a výstupu. Nějaké nápady?
>
> Druhá věc je, že určitě nejsem provní ani poslední koho něco takového 
> napadlo. Má tu někdo zkušenosti s používáním nějkakého takového již 
> hotového, nejlépe open source projektu?
------------- další část ---------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#define F_CPU		(20000000UL)

#define F_CPUkor	(F_CPU + ((F_CPU * (int8_t)SIGROW.OSC20ERR5V) / 1024L))
#define uartBaud(br) ((float) (F_CPUkor*64 / (16*(float)br)) + 0.5)

class clSerStream { // ==================================================================

friend clSerStream & operator<<(clSerStream & ss, unsigned char ch);
friend clSerStream & operator<<(clSerStream & ss, char ch);
friend clSerStream & operator<<(clSerStream & ss, bool b);

private:	
	enum {
		cNumSepLen = 5,
		cEndlLen = 3
	};
	static bool isUsed;
	bool lastWasNum;
	char numSeparator[cNumSepLen];
	uint8_t digitsSend;
	
public:
	char endl[cEndlLen];
	bool autoSepNums;
	bool charVal;
	uint8_t bytesSend;
	
	clSerStream(uint16_t bd, bool altPort) { // -----------------------------------------
		if (isUsed) return;
		if (altPort) PORTMUX.CTRLB|=PORTMUX_USART0_ALTERNATE_gc;
		// alt: RxD - PORTA.2, TxD - PORTA.1 (xnano)
		USART0_CTRLA=0;								// int off, 485 off
		USART0_CTRLB=USART_RXEN_bm+USART_TXEN_bm;	// tx en, rx en
		USART0_CTRLC=USART_CMODE_ASYNCHRONOUS_gc+USART_CHSIZE_8BIT_gc;
		USART0_BAUD=uartBaud(bd);
		endl[0]=10; endl[1]=13; endl[2]=0;
		lastWasNum = 0;
		numSeparator[0]=','; numSeparator[1]=' '; numSeparator[2]=0;
		autoSepNums = false;
		charVal = false;
		bytesSend = 0;
	}
	~clSerStream() { // -----------------------------------------------------------------
		USART0_CTRLB=0;
		isUsed=false;
	}
	
	void putB(uint8_t c) { // -----------------------------------------------------------
		while ((USART0.STATUS & USART_DREIF_bm) == 0);
		USART0.TXDATAL=c;
		bytesSend++;
	}
	uint8_t getB() { // -----------------------------------------------------------------
		while(!(USART0_STATUS & USART_RXCIF_bm));
		return USART0_RXDATAL;
	}
	void sendStr(char c[]) { // ---------------------------------------------------------
		for (signed char n=0; c[n]!=0; n++)	putB(c[n]);
		lastWasNum = false;
	}
	void sendUint32(uint32_t xx) { // ---------------------------------------------------
		char t[10];
		signed char n;
		long x;
		digitsSend = 0;
		
		if (autoSepNums && lastWasNum) sendStr(numSeparator);
		
		if (xx==0) {putB('0'); digitsSend++; return;}
		x=xx;
		for (n=0; n<10 && x>0; n++) {
			t[n] = x % 10 + '0';
			x /= 10;
		}
		for (n-=1; n>=0; n--) {putB(t[n]); digitsSend++; }
		
		lastWasNum = true;
	}
	void sendInt32(int32_t xx, bool disMinus=false) { // --------------------------------
		if (xx<0) {
			if (autoSepNums && lastWasNum) sendStr(numSeparator);
			if (!disMinus) putB('-');
			sendUint32(-xx);
		} else sendUint32(xx);
	}
	void sendFloat(float f) { // --------------------------------------------------------
		bool tSep = autoSepNums;
		
		if (f <= __LONG_MAX__ || -f <= __LONG_MAX__) {
			int32_t i32 = f;
			sendInt32(i32);
			autoSepNums = false;
			putB('.');
			
			if (digitsSend<8) {
				if (f>=0.1 || f<=-0.1) {
					int32_t dek=1;
					for (digitsSend=8-digitsSend; digitsSend>0; digitsSend--) dek *= 10;
					float ff = (f-(float)i32) * (float)dek;
					sendInt32((int32_t)ff, true);
				} else {
					// moc male zatim nejsou
					sendStr("00nic");
				}
			}
		} else {
			// velke zatim nejsou
			sendStr("ABS>MAX");
		}
		autoSepNums = tSep;
		lastWasNum = true;
	}
	void setNumSeparator(char * t, bool sw) { // ----------------------------------------
		for (char n=0; n<cNumSepLen; n++) {
			numSeparator[n]=t[n];
			if (t[n]==0) break;
		}
		numSeparator[cNumSepLen-1] = 0;
		autoSepNums = sw;
	}
};
bool clSerStream::isUsed = false;

clSerStream & operator<<(clSerStream & ss, float val) { ss.sendFloat(val); return ss; }
clSerStream & operator<<(clSerStream & ss, double val) { ss.sendFloat(val); return ss; }
clSerStream & operator<<(clSerStream & ss, uint32_t val) { ss.sendUint32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, int32_t val) { ss.sendInt32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, uint16_t val) { ss.sendUint32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, int16_t val) { ss.sendInt32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, unsigned char ch) {
	if (ss.charVal) ss.sendUint32((uint32_t)ch);
	else {ss.putB(ch); ss.lastWasNum = false;}
	return ss;
}
clSerStream & operator<<(clSerStream & ss, char ch) {
	if (ss.charVal) ss.sendInt32((int32_t)ch);
	else {ss.putB(ch); ss.lastWasNum = false;}
	return ss;
}
clSerStream & operator<<(clSerStream & ss, char* t) { ss.sendStr(t); return ss; }
clSerStream & operator<<(clSerStream & ss, bool b) {
	if (ss.autoSepNums && ss.lastWasNum) ss.sendStr(ss.numSeparator);
	if (b) ss.sendStr("true"); 
	else ss.sendStr("false");
	ss.lastWasNum = true;
	return ss;
}

clSerStream serOut(19200, true); // =====================================================

unsigned long long LLL = 1234567890123456789;

#define LED_bit		5	// bit s LEDkou
#define TL_bit		4	// bit s tlačítkem

#define TL_jeStisk	((PORTB.IN & (1<<TL_bit)) == 0)		// podmínka právě je stisklé tlačítko
#define TL_neniStisk ((PORTB.IN & (1<<TL_bit)) != 0)	// podmínka není stisklé

volatile unsigned int	ms=0;
volatile char			msSync=0;

void atomMs0() { // =====================================================================
	__asm__("cli");
	ms=0;
	__asm__("sei");
}

unsigned int atomMsRead() { // ==========================================================
	unsigned int p;
	
	__asm__("cli");
	p=ms;
	__asm__("sei");
	return p;
}

void cekej(unsigned int n) { // =========================================================
	atomMs0();
	
	while(atomMsRead()<=n) {
		
	}
}

int main(void) {
	// ----------------------------------------------------------------------------------
	_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);		// nedelit - bude 20 MHz
	// ----------------------------------------------------------------------------------
	PORTA.DIR=0b00000010;						// 1 TXD out / 2 RXD PU en
	PORTA.PIN2CTRL=PORT_PULLUPEN_bm;			// zapnout pull-up pro aby nezapojené RXD negenerovalo data
	PORTB.DIR=0b00100000;						// 4 tlacitko on=0, 5 LED on=0
	PORTB.PIN4CTRL=PORT_PULLUPEN_bm;			// zapnout pull-up pro tlačítko
	PORTB.OUTSET = 1<<LED_bit;					// aby LEDka na začátku nesvítila
	// ----------------------------------------------------------------------------------
	TCA0_SINGLE_CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc;		// použít přímo frekvenci procesoru (děleno 1)
	TCA0_SINGLE_CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;	// NORMAL - jen čítat
	TCA0_SINGLE_PER = F_CPU / 1000UL;					// perioda čítání bude tisícina F_CPU
	TCA0_SINGLE_INTCTRL = TCA_SINGLE_OVF_bm;			// přerušení od přetečení periody
	TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm;			// smazat případné předchozí visící přerušení
	TCA0_SINGLE_CTRLA |= TCA_SINGLE_ENABLE_bm;			// povolit čítač
	// ---------------------------------------------------------------------------------
	__asm__("sei");

	
	uint32_t ui = 123456789;
	long li = -123456789;
	char ccc[] = " c ";
	int i = 1234;
	char chr = 123;
	bool test1, test2;
	
	serOut.autoSepNums = 1;
	
    while (1) {
		test1 = ui & 1;
		test2 = ui & 2;
		serOut.charVal = test1;
		serOut.autoSepNums = test2;
		serOut << test1 << test2 << serOut.endl;
		
		//serOut << "a " << ui << " b " << 1234 << ccc << serOut.endl;
		//serOut << ui << i << chr << serOut.endl;
		serOut << li << -123456 << serOut.endl;
		
		serOut << (unsigned char)' ' << '*' << serOut.endl << serOut.endl;
		ui++;
		
		//serOut << 12.3456789 << 555.7777777 << 1.111111111 << -987.654321 << 0.123456789 << 0.00333333 << serOut.endl;
		
		cekej(1000);
    }
}

ISR (TCA0_OVF_vect) { // ================================================================
	ms++;
	msSync=1;
	
	TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm;
}


Další informace o konferenci Hw-list