Hallo,

Ik probeer een Arduino c++ library voor een LPD8806 RGB ledstrip om te zetten naar C voor avr studio en stoot daarbij op enkele vragen.

1) Is het correct om


uint8_t *pixels;
if(pixels != NULL) free(pixels);

en

if(NULL != (pixels = (uint8_t *)malloc(numBytes))) {}

om te zetten naar

 uint8_t *pixels;
if(pixels) free(pixels);

en

if((pixels = (uint8_t *)malloc(numBytes))) {}

2) kan ik byte veriabelen vervangen door uint8_t

// Convert separate R,G,B into combined 32-bit GRB color:
uint32_t LPD8806::Color(byte r, byte g, byte b) {
  return ((uint32_t)(g | 0x80) << 16) |
         ((uint32_t)(r | 0x80) <<  8) |
                     b | 0x80 ;
}

3) Wanneer ik in onderstaande functie delay(wait) vervang door _delay_ms(wait) krijg in volgende foutmelding...

Error 23 __builtin_avr_delay_cycles expects an integer constant. c:\program files\atmel\atmel studio 6.0\extensions\atmel\avrgcc\3.4.1.95\avrtoolchain\bin\../lib/gcc/avr/4.6.2/../../../../avr/include/util/delay.h 164 28 ledstrip

#include <util/delay.h>
// Fill the dots progressively along the strip.
void colorWipe(uint32_t c, uint8_t wait) {
  int i;

  for (i=0; i < numPixels(); i++) {
      setPixelColor(i, c);
      show();
      delay(wait);
  }
}

AVR studio 5 doet ook c++ afaik.*

Wat 3 betreft: heb je #define F_CPU opgegeven? (in Hz)

Wat 2 betreft: waarschijnlijk wel, zolang er geen gekke dingen worden gedaan in de constructor van een byte en een byte geen opperators overload.

*EDIT: studio 4 ook, het hangt van de compiler af, en dat is net als bij arduino gCC.

[Bericht gewijzigd door Lucky Luke op (16%)]

malloc() heb ik bij een AVR nog nooit gebruikt. Kan je het niet met een simpele array[] doen?

Wat die _delay_ms(wait) betreft: dat is geen goed idee. Iets als _delay_ms(12.345) kan gerust. De compiler gaat zelf de delay-lus berekenen, en het resultaat bestaat uit enkele regels assembly-code.
Wanneer de delay-tijd tijdens het compileren onbekend is, zit er niets anders op dan _delay_ms(wait) te vertalen naar een gróóte blok assembly-code, die zelf de delay-lus gaat berekenen en bovendien met floats gaat werken.

Zelf doe ik het zo:


void delay_ms(unsigned int ms)
{
    for (; ms > 0; ms--) {
	_delay_ms(0.99);
    }
}

	delay_ms(wait);

Dat neemt amper plaats in, en werkt net zo goed.

Op 11 februari 2013 18:54:15 schreef retro man:
1) Is het correct om


uint8_t *pixels;
if(pixels != NULL) free(pixels);

en

if(NULL != (pixels = (uint8_t *)malloc(numBytes))) {}

om te zetten naar

 uint8_t *pixels;
if(pixels) free(pixels);

en

if((pixels = (uint8_t *)malloc(numBytes))) {}

Waarom zou je dat willen? Het wordt er niet duidelijker van en het is onnodig. Als je de NULL constante nodig hebt is dat een kwestie van stdlib.h includen.

Malloc op een microcontroller is iets wat ik liever niet doe. Omdat de lengte van je ledstrip waarschijnlijk niet verandert kun je prima met een vaste lengte array af.

Op 11 februari 2013 18:54:15 schreef retro man:
Hallo,

Ik probeer een Arduino c++ library voor een LPD8806 RGB ledstrip om te zetten naar C voor avr studio en stoot daarbij op enkele vragen.

In principe kan je (met wat beperkingen) ook C++ met AVR studio doen (zie ook http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus en http://avr-cpp-lib.sourceforge.net/). Ik heb de indruk dat de Ardiuino toolchain dezelfde is als die van AVR studio, en dat het enige echte verschil is een library met Arduino specifieke functies (zoals digitalWrite) en de IDE.

Echter de alle code die je hier neergezet hebt lijkt gewoon C te zijn.

1) Is het correct om


uint8_t *pixels;
if(pixels != NULL) free(pixels);

Ik mag hopen dat dit niet zo letterlijk in de code staat en dat de pixels pointer nog geïnitialiseerd wordt voor de if statement. De if statement is overigens overbodig omdat de free() functie niets doet als de pointer NULL is.

en

if(NULL != (pixels = (uint8_t *)malloc(numBytes))) {}

om te zetten naar

 uint8_t *pixels;
if(pixels) free(pixels);

en

if((pixels = (uint8_t *)malloc(numBytes))) {}

De code van voor en na jouw aanpassing is geldig in zowel C als C++. De getoonde varianten zijn equivalent en zullen naar alle waarschijnlijkheid tot precies dezelfde machine code leiden. De vraag is waarom je dit zou aanpassen.

2) kan ik byte veriabelen vervangen door uint8_t

Dat kan, of je doet een typedef uint_8 byte;

Op 11 februari 2013 20:09:58 schreef Patrick de Zeester:
Ik heb de indruk dat de Ardiuino toolchain dezelfde is als die van AVR studio, en dat het enige echte verschil is een library met Arduino specifieke functies (zoals digitalWrite) en de IDE.

Klopt, zowel AVR studio als Arduino gebruiken GCC-AVR, en de AVR-binutils van GNU onder water.

Oftewel: Als arduino je C++ code vreet, zal AVR studio het ook wel lusten.

Blijft over dat malloc gebruiken in een microcontroller uiterst dubieus is...

[Bericht gewijzigd door blurp op (17%)]


if(pixels != NULL) free(pixels);
// Omzetten naar
if(pixels) free(pixels);

De code van voor en na jouw aanpassing is geldig in zowel C als C++.

Enkel als avr-gcc "NULL" vertaalt naar "0". En waarschijnlijk doet hij dat ook. Maar het lijkt me geen goed idee, dat zomaar voetstoots aan te nemen.
Daarbij komt, zoals je zelf al aangeeft, dat de broncode iets kleiner wordt, maar dat de uiteindelijke machinecode net zo groot blijft.

NULL pointer zijn trouwens best geinig op een 8051. Adres 0 is gewoon een valid stuk RAM... Heb er ooit toch eens 2 dagen naar gezocht... :(

Zover ik weet is free() geheel niet verplicht om de pointer op NULL te zetten!

if(pixels != NULL) free(pixels);
// Omzetten naar
if(pixels) free(pixels), pixels = NULL;

void free(void *ptr) kan ptr niet op null zetten, want free heeft het adres van ptr niet.
Verder geeft free geen waarde terug, dus daarmee kun je ptr ook niet op null zetten.

Bedakt voor de hulp iedereen. Dankzij jullie tips heb ik de library ondertussen werkende gekregen. Wel nog met een paar warnings waar jullie mij misschien ook nog kunnen mee helpen.

implicit declaration of function 'memset' [-Wimplicit-function-declaration]
incompatible implicit declaration of built-in function 'memset' [enabled by default]
'b' may be used uninitialized in this function [-Wuninitialized]
'g' may be used uninitialized in this function [-Wuninitialized]
'r' may be used uninitialized in this function [-Wuninitialized]
uint32_t Wheel(uint16_t WheelPos)
{
	uint8_t r, g, b;
	switch(WheelPos / 128)
	{
		case 0:
		r = 127 - WheelPos % 128;   //Red down
		g = WheelPos % 128;      // Green up
		b = 0;                  //blue off
		break;
		case 1:
		g = 127 - WheelPos % 128;  //green down
		b = WheelPos % 128;      //blue up
		r = 0;                  //red off
		break;
		case 2:
		b = 127 - WheelPos % 128;  //blue down
		r = WheelPos % 128;      //red up
		g = 0;                  //green off
		break;
	}
	return(Color(r,g,b));
}

volledige bib


/****************************************************

LPD8806 RGB Ledstrip library

****************************************************/

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>


uint16_t numLEDs, numBytes;
uint8_t *pixels;


void SPI_init(void){

	DDRB = ((1<<DDB3)|(1<<DDB5)|(1<<DDB2)); //spi pins on port b MOSI SCK,SS outputs

	SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPOL)|(1<<CPHA));  // SPI enable, Master, f/16

}

char SPI_Transmit(char cData){

	SPDR = cData;
	while(!(SPSR & (1<<SPIF)))
	;
	return SPDR;
}

void delay_ms(unsigned int ms)
{
	for (; ms > 0; ms--) {
		_delay_ms(0.99);
	}
}

void updateLength(uint16_t n) {
	uint8_t latchBytes = (n + 31) / 32;
	if(pixels != NULL) free(pixels); // Free existing data (if any)
	numLEDs    = n;
	n         *= 3; // 3 bytes per pixel
	numBytes   = n + latchBytes;
	if(NULL != (pixels = (uint8_t *)malloc(numBytes))) { // Alloc new data
	memset( pixels   , 0x80, n);          // Init to RGB 'off' state
	memset(&pixels[n], 0   , latchBytes); // Clear latch bytes
} else numLEDs = numBytes = 0; // else malloc failed
// 'begun' state does not change -- pins retain prior modes
}


// Set pixel color from 'packed' 32-bit GRB (not RGB) value:
void setPixelColor(uint16_t n, uint32_t c) {
	if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
	uint8_t *p = &pixels[n * 3];
	*p++ = (c >> 16) | 0x80;
	*p++ = (c >>  8) | 0x80;
	*p++ =  c        | 0x80;
}
}

void show(void) {
	uint8_t  *ptr = pixels;
	uint16_t i    = numBytes;

	while(i--) {
		SPI_Transmit(*ptr++);
	}
}

uint16_t numPixels(void) {
	return numLEDs;
}

// Convert separate R,G,B into combined 32-bit GRB color:
uint32_t Color(uint8_t r, uint8_t g, uint8_t b) {
	return ((uint32_t)(g | 0x80) << 16) |
	((uint32_t)(r | 0x80) <<  8) |
	b | 0x80 ;
}

// Chase one dot down the full strip.
void colorChase(uint32_t c, uint8_t wait) {
	int i;

	// Start by turning all pixels off:
	for(i=0; i<numPixels(); i++) setPixelColor(i, 0);

	// Then display one pixel at a time:
	for(i=0; i<numPixels(); i++) {
		setPixelColor(i, c); // Set new pixel 'on'
		show();              // Refresh LED states
		setPixelColor(i, 0); // Erase pixel, but don't refresh!
		delay_ms(wait);
	}

	show(); // Refresh to turn off last pixel
}

// Fill the dots progressively along the strip.
void colorWipe(uint32_t c, uint8_t wait) {
	int i;

	for (i=0; i < numPixels(); i++) {
		setPixelColor(i, c);
		show();
		delay_ms(wait);
	}
}

//Input a value 0 to 384 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(uint16_t WheelPos)
{
	uint8_t r, g, b;
	switch(WheelPos / 128)
	{
		case 0:
		r = 127 - WheelPos % 128;   //Red down
		g = WheelPos % 128;      // Green up
		b = 0;                  //blue off
		break;
		case 1:
		g = 127 - WheelPos % 128;  //green down
		b = WheelPos % 128;      //blue up
		r = 0;                  //red off
		break;
		case 2:
		b = 127 - WheelPos % 128;  //blue down
		r = WheelPos % 128;      //red up
		g = 0;                  //green off
		break;
	}
	return(Color(r,g,b));
}

void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 384; j++) {     // 3 cycles of all 384 colors in the wheel
    for (i=0; i < numPixels(); i++) {
      setPixelColor(i, Wheel( (i + j) % 384));
    }  
    show();   // write all the pixels out
    delay_ms(wait);
  }
}

// Slightly different, this one makes the rainbow wheel equally distributed
// along the chain
void rainbowCycle(uint8_t wait) {
	uint16_t i, j;
	
	for (j=0; j < 384 * 5; j++) {     // 5 cycles of all 384 colors in the wheel
	for (i=0; i < numPixels(); i++) {
		// tricky math! we use each pixel as a fraction of the full 384-color wheel
		// (thats the i / strip.numPixels() part)
		// Then add in j which makes the colors go around per pixel
		// the % 384 is to make the wheel cycle around
		setPixelColor(i, Wheel( ((i * 384 / numPixels()) + j) % 384) );
	}
	show();   // write all the pixels out
	delay_ms(wait);
}
}

Voor de memset() functie moet je <string.h> includen.

In de Wheel() functie blijven de r,g en b variabelen ongeïnitialiseerd als WheelPos/128 geen 0, 1, of 2 is. In dat geval is waarde die in deze variabelen terecht komt onvoorspelbaar. Wellicht dat deze situatie nooit voorkomt in dit programma, maar dat weet de compiler niet. De oplossing is om de r, g en b variabelen te initialiseren voor de switch, of een default clause op te nemen in de switch die de r, g en b variabelen een bepaalde waarde geeft.

WheelPos/128 wordt nooit wat anders dan 0, 1, of 2. met een default op te nemen is het probleem idd opgelost.

het memset() probleem zat idd bij <string.h> die niet geinclude was.

bij deze is mijn probleem geheel opgelost. bedankt iedereen.