Arduino snelheid

Door Blokker_1999 op zondag 17 november 2013 19:09 - Reacties (16)
Categorie: /var, Views: 5.091

Dit weekend heb ik me bezig gehouden met wat leuk speelgoed. 2 grote LED matrix displays van elks 16x64. Deze displays zijn afkomstig uit de interne bestemmingsaanduiders van de M6 rijtuigen.

Deze displays vormden een leuke uitdaging. Ze worden voor ons op maat gemaakt, maar eigenlijk weten we zeer weinig van deze displays. De leverancier van deze displays gaf recent een interessante demo bij ons op kantoor met deze displays voor een ander project. Bij deze demo gebeurde de aansturing met behulp van een arduino microcontroller. Daar ik thuis zelf zo een controller heb liggen dacht ik: dat moet ik ook eens proberen.

De uitdaging was alleen iets groter dan eerst voorzien. De elektronische schemas van het display zijn welliswaar beschikbaar in de datasheet van de displays, maar de aanduidingen op die schemas zijn onleesbaar. Met veel geduld, een multimeter en scherpe meetpennen die door de beschermlak gaan toch het schema kunnen herconstrueren en de aansluitingen kunnen bepalen, tijdens het weekend nog altijd sneller dan deze aan de leverancier te vragen ;).

Direct volgde de volgende tegenslag. De meeste voorbeelden die je online vind gaan er van uit dat je een datalijn hebt per rij die je gaat aansturen. dat geeft dat je een volledige kolom in 1 keer kunt weergeven en dat je dus kolom per kolom kan weergeven. Helaas, niet op deze displays. Omdat we 16 rijen hebben heeft men ervoor gekozen deze achter een 1-of-8 Decoder/Demultiplexer te plaatsen waardoor je slechts 1 rij gelijktijdig kan laten oplichten. Als ik kolom per kolom wens op te bouwen moet ik dan ook elke LED apart gaan laten oplichten wat de scantime over het display enorm de hoogte indrijft. De eerste code die ik geschreven heb paste dit principe toe, maar bleek uiteindelijk onwerkbaar.

Na even mijn hersenen te pijnigen er toch achter gekomen hoe het dan wel moet. Je stuurt de data voor de hele lijn in 1 keer door de schuifregisters, latcht deze vast, zet je uitgang hoog voor die rij, en terwijl die rij oplicht laad je de data voor je volgende rij in je schuifregister. Eenmaal ingeladen, even je uitgang laag brengen, latch loslaten, vastzetten, van rij verspringen en uitgang terug hoog zetten.

Als dit snel genoeg gaat krijg je zo een proper beeld van je display. … Maar hier komt arduino op zich te kort. Omdat de arduino software een eigen programeertaal heeft gaat er redelijk wat snelheid verloren. Na het herschrijven van de software had ik dan ook een enorm flikkerend (en dus storend) beeld.

Ik ben dan op het internet op zoek gegaan, en je kan blijkbaar digitalWrite(PIN STATE); ook vervangen daar volwaardige C code. Volgens testen die ik ben tegengekomen gaat het met C-stijl code ongeveer 10x sneller. Nadat ik de 2 meest gebruikte pinnen in mijn code had omgevormd was het beeld op het display gewoon stabiel te noemen. Ik ben dan nu ook bezig met de andere pinnen ook nog om te vormen.

Arduino heeft alle pinnen netjes genummerd, maar om deze rechtstreeks aan te spreken moet je deze vertalen naar het juiste poortnummer van je controller, hiervoor kan je op het internet figuren vinden, ook op de arduino website zoals voor mijn eigen Mega2560.

Het direct aansturen van de pinnen doe je op volgende manier:

Een poort hoog zetten:
PORT{letter} |= _BV(P{letter}{number});

Een poort laag zetten:
PORT{letter} &= ~_BV(P{letter}{number});

Een voorbeeld van Pin13 op mijn Mega2560 (poort B7):
PORTB |= _BV(PB7); //PIN13 hoog
PORTB &= ~_BV(PB7); //PIN13 laag

Wanneer snelheid belangrijk is loont het dus om de arduino code te vervangen door C-stijl code die de AVR GCC compiler kan verstaan. Nog beter is uiteraard om de arduino omgeving volledig links te laten liggen en helemaal in C-stijl te gaan programmeren.

http://tweakers.net/ext/f/UxqcP4BaqR8oUSjjr6y7iDUw/medium.jpg

Volgende dingen op het programma: mijn ASCII tabel verder uitwerken (op dit moment enkel het alfabet in hoofdletters), display uitbreiden naar een formaat dat vergelijkbaar is zoals we het in de trein terug vinden, animaties toevoegen (text scrolling), communicatieprotocol toevoegen, … . Maar ook bestaat de kans dat ik de arduino ga inruilen voor iets anders, zoals een pandabord met sturing via de GPIO pinnen.

Volgende: Help, ze willen mij dood. 01-'14 Help, ze willen mij dood.
Volgende: De trein heeft altijd vertraging 05-'13 De trein heeft altijd vertraging

Reacties



Door Tweakers user Youran, zondag 17 november 2013 21:37

Wil je de arduino omgeving verlaten, dan raad ik je sterk aan eens Atmel studio te bekijken! Samen met een USBasp programmer (2 euro op eBay) kun je vervolgens je Mega programmeren via de ISP header. DŠn pas begin je goed te begrijpen hoe een microcontroller werkt ;)

[Reactie gewijzigd op zondag 17 november 2013 21:37]


Door Tweakers user Damic, zondag 17 november 2013 22:59

Die atmel studio is leuk maar bloated :( gebruik zelf avr project ide. Is licht en luchtig en doet praktisch hetzelfde.

Door Tweakers user SA007, maandag 18 november 2013 11:20

Overigens is het niet nodig om van de arduino ide af te stappen, je kan simpelweg de arduino libraries niet meer gebruiken, op de achtergrond is het gewoon avr-gcc en avrdude.

De arduino libs zijn inderdaad vrij overkill, maar ook jouw code kan nog optimized worden.

Bijv als je een pin hoog wil zetten waarvan je weet dat hij laag is of laag als hij hoog is (toggle dus, werkt alleen als hij output staat).

PINB = 0x04; // voor PORTB2

In jouw code zou zit zijn:
PORTB |= _BV(PB2);
Nu zal _BV(PB2) waarschijnlijk wel door avr-gcc naar 0x04 gereduceerd worden, maar de |= wordt effectief:
<temp> = PORTB;
temp | 0x04;
PORTB = temp;

Wat dus flink langer is, vooral op een software SPI clock ofzo is dat erg merkbaar.

Door Tweakers user RoadRunner84, maandag 18 november 2013 12:00

#define BIT(n) (1 << n)
PORTB |= BIT(7); // pin 13 hoog
PORTB = (PORTB & ~BIT(4)) | BIT(7); // tegelijk PB4 laag en PB7 hoog

Ik werk zelf veel met de MSP430 microcontrollers van Texas Instruments, deze zijn ook te programmeren via Energia, een modificatie op Arduino voor deze controllers.
Ik weet niet zeker hoe e _BV() macro werkt, maar ik vermoed dat deze toch een zekere overhead introduceert. Feitelijk wil je van een poort aangeven welke pin je wilt benaderen, het is tegenstrijdig om de poort expliciet te vernoemen en dan de pin te benaderen via zijn Arduino alias.

PORTB ^= BIT(3)|BIT(4); // toggle PB3 en PB4
PORTB = BIT(1)|BIT(4)|BIT(7); // zet alle PB pinnen laag, behalve PB1, PB4 en PB7, die worden hoog

PORTB = (PORTB ^BIT(2)) |BIT(5); // Toggle PB2 en zet PB5 hoog

Door Tweakers user Blubber, maandag 18 november 2013 12:29

Die Arduino was een paar jaar geleden een leuk speeltje, maar is wat mij betreft vrij hard ingehaald door bijvoorbeeld de Teensy 3.0. De Teensy is veel sneller, ordes grote sneller dan de Arduino, hij is kleiner en hij is goedkoper, wat wil je nog meer?

De Teensy is ook nog eens Arduino compatibel, dus als je niet van die "handige" Arduino omgeving af wilt is er geen probleem :+.

Edit: linkje naar de website van PJRC, de maker van de Teensy.

[Reactie gewijzigd op maandag 18 november 2013 12:33]


Door Tweakers user RobV, maandag 18 november 2013 17:24

"Omdat de arduino software een eigen programeertaal heeft gaat er redelijk wat snelheid verloren. "

Dit klopt niet helemaal. De arduino code wordt van C++ naar native Atmel assembly gecompileerd door GCC. Alleen zelf assembly schrijven kan een performance winst opleveren, alleen de moeite waard voor tight loops.

De digitalWrite() staat erom bekend traag te zijn. Dat is zo, omdat ze een functie is die op alle atmels werken moet. Als directe port toegang niet handig is, stel ik voor dat je kijkt naar fastDigitalWrite() die is al vele malen sneller (nooit zo snel als directe toegang waar je 8 bits tegelijk kan zetten in 1 instructie)

Om dan gelijk de Arduino omgeving links te laten liggen. Het doel is fast prototyping. Als je een SD kaart wilt uitlezen (als proof of concept) wil je niet eerst in de datasheet uitzoeken welke port/bit je moet pakken. In een later stadium kun je optimizen.

Door Tweakers user diabolofan, maandag 18 november 2013 18:33

Ziet er goed uit! Ook wel eens aan het kloten geweest met een led display, maar in verband met te weinig kennis op het gebied van elektro en embedded systems is het me toen niet gelukt.

Zelf momenteel aan het kijken naar controllers van GHI Electronics. En dan met name de G120HDR Module Rev2 . Lekker Micro .NET Framework erop, maar ben wel bang dat de performance niet al te best zal zijn.

Door Tweakers user Eloy, maandag 18 november 2013 19:34

Wat een modern toetsenbord :P

Door Tweakers user Blokker_1999, dinsdag 19 november 2013 07:31

RobV schreef op maandag 18 november 2013 @ 17:24:Om dan gelijk de Arduino omgeving links te laten liggen. Het doel is fast prototyping. Als je een SD kaart wilt uitlezen (als proof of concept) wil je niet eerst in de datasheet uitzoeken welke port/bit je moet pakken. In een later stadium kun je optimizen.
Maar wanneer je fast prototyping niet snel genoeg blijkt te zijn om de opdracht te verwerken, en indien blijkt dat dit voor een stuk afhangt van de programmeeromgeving dan is dat niet positief te noemen voor het systeem.

Begrijp me niet verkeerd, ik snap wel waarom ze het doen, en ik snap de voordelen van hun systeem. Maar het is spijtig dat ze in hun eigen referentiehandleiding onder de pagina voor digitalWrite hier geen melding van maken, dat je als gebruiker zelf moet gaan ontdekken dat dit een verdomd trage functie is en dat het effectief veel sneller kan.

Door Tweakers user royb3, donderdag 21 november 2013 15:05

Ik gok dat het een unicomp, houder van de patenten van de ibm model m, is. vanwege dat rare stukje linksboven.

Door Tweakers user Blokker_1999, donderdag 21 november 2013 17:14

rare stukje? Bedoel je de DVI kabel die er naast ligt?

Maar het is inderdaad een unicomp, was goedkoper dan een echte M.

Door Tweakers user HRN_NL, woensdag 2 april 2014 22:46

Per toeval ben ik in bezit gekomen van een paar van deze displays. Daar er een groot aluminium koelplaat over de achterzijde zit, heb ik een beetje problemen met het herleiden van de aansluiting. De connector in het midden is overduidelijk de aansluiting van de voeding. De connectors links en rechts roepen veel vraagtekens op. Ik krijg wel wat op het scherm (kolom 1 t/m 32) maar dat herhaalt zich over kolom 33 t/m 64. Kan je het schema of de aansluitingen van de pennen beschikbaar stellen? Daarnaast ben ik wel geÔnteresseerd in de sketch die je gebruikt op de bijgevoegde foto. Bvd :)

Door Tweakers user Blokker_1999, donderdag 3 april 2014 07:38

De displays die ik hier gebruik zijn custom build en de aansluitingen gaan dus niet overeen komen. Hoe stuur je deze aan zodat je ziet dat het beeld zich herhaald? Ben je zeker dat het beeld niet gewoon doorloopt (dat je steeds dezelfde 32 bits doorstuurd)? In het geval van mijn displays moet je de data lijn per lijn insturen. Heb je eenmaal een lijn ingeladen kan je de data latchen en dan kan je de enable lijn hoogzetten zodat er beeld op komt terwijl je zelf naar de volgende lijn gaat. Opnieuw data inlezen, enable laag, latch off, latch on, enable hoog en naar de volgende lijn ...

Door Tweakers user HRN_NL, zondag 6 april 2014 22:43

Bedankt voor je reactie. De displays die ik heb bemachtigd (2x geel en 2x rood) lijken erg op de getoonde foto. De gele versie heeft de markering LS1026 BS99.600060100. De koelplaat heeft 6x M4 boutjes. Het sterke vermoeden heb ik dat de leverancier vlak bij Schiphol een vestiging heeft. Als ik je reactie goed lees, moet ik niet rekenen met 16 regels maar met 32 regels diep… Immers halverwege het display zit bij iedere regel een onderbreking (zichtbaar aan het sporenplan aan de SMD LED zijde). En dan het genoemde protocol er op los laten... Ik ben niet zo’n programmeur maar zal een nieuwe poging wagen.

Door Tweakers user Blokker_1999, maandag 7 april 2014 14:20

Ik vermoed dat het dat inderdaad zal zijn. De datalijn loopt in principe gewoon door naar het volgende display waardoor je data moet toezenden van de laatste LED naar de eerste in mijn geval.

Reageren is niet meer mogelijk