Ik ben op m'n werk bezig met een wireless modem (GSM en GPRS), die on board een PIC16F88 heeft om de boel in goede banen te leiden, en als een uitgebreide watchdog allerlei dingen in de gaten te houden. De in assembly geschreven firmware is op dit moment zo'n 2k instructies, met nog ongeveer 0,5k in flash opgeslagen ASCII, plus een stukje EEPROM voor zaken die aangepast moeten kunnen worden. Zo'n twee maanden geleden heb ik in de firmware iets gewijzigd waardoor een belangrijk deel niet meer werkte. Ik ben daarna met andere delen verder gegaan in de hoop dat het zou gaan dagen waar het aan lag dat het eerste deel niet meer werkte. Vandaag vond ik het probleem: stack overflow. De PIC16 heeft een 8 niveau's diepe hardware stack die niet toegankelijk is en geen overflow error geeft. Mijn hoofdprogramma gebruikt 7 niveau's, en de interrupt had er altijd maar 1 nodig. Totdat ik subroutines ging gebruiken in de interrupt routine om die in te korten (twee maanden geleden). Voila, 9 stack niveau's en de boel loopt hopeloos vast zonder pardon. De subroutines heb ik weer uit de interrupt routine gehaald en nu loopt het weer als een zonnetje.

De firmware is niet eens heel ingewikkeld. Maar aan 7 geneste subroutines zit je zo.

De moraal van dit verhaal: heb je een net iets ingewikkeldere firmware met een net even uitgebreidere interrupt routine, dan is een PIC16 vrij snel uitgeput qua mogelijkheden. Tel daarbij op het eeuwige, constante en irritante bank switching, slechts 1 werkregister, geen geïndexeerde addresseringsmogelijkheden in de processorkern, het gegoochel met missende adresbits, etc. etc. etc. dan snap je dat vanaf nu de PIC16 serie voor mij compleet afgedaan heeft.

Wat nu? Ik weet het niet.

http://fuzzcraft.com/pics/dinaf_gsm-5.gif

Ik ook niet, maar toch een reactie.

Zeven nivo's van geneste subroutines vind ik eerlijk gezegd behoorlijk veel.
Ik heb ooit, voor de lol, een programma'tje geschreven om de diepte van het nesten te bepalen en kwam bij complexe assembler programma's op niet meer dan 4. Zelfs bij door Proton gecompileerde programma's met lastige libraries kwam ik niet verder dan 5.
Eerlijk gezegd denk ik zo'n hoge mate van subroutines nesten de duidelijkheid (lees: onderhoudbaarheid) ook niet altijd ten goede komt. Op nivo 6 weet je nauwelijks meer wat er op nivo 3 eigenlijk aan de hand was.

Je opmerking dat je subroutines gebruikt om de interrupt routine in te korten snap ik niet. Het aantal regels wordt minder, maar het aantal instructies neemt alleen maar toe (Call en Return).
Subroutines schrijf je om 1) vanaf meerdere plekken in je programma bepaalde functionaliteit aan te roepen of 2) om een programma portable/herbruikbaar te maken (voorbeeld: ik heb een generiek stuk programma dat de tijd uit een GPS string haalt, maar de manier waarop ik dat presenteer verschilt van klok tot klok. Dit laatste zit in de subroutine DrawClock die dus per implementatie verschilt. Het zgn Model-View-Controller principe waarbij de View verschilt), maar je gebruikt ze niet om een programma 'korter' te maken.

Om het probleem met de stack te omzeilen heb je natuurlijk ook de mogelijkheid om macro's te gebruiken. Een macro is zelfs in te zetten als ware het een functie met parameters, lokale variabelen en lokale labels. Het verschil met 'echte' functies is natuurlijk dat ze (veel) meer instructies opleveren.

Alternatief: De 18F
- Heeft een veel grotere (31 levels) stack die wel softwarematig toegankelijk is (maar dat wil je toch alleen maar als je functies met parameters gebruikt. In principe kun je dat omzeilen door vaste variabelen te gebruiken die in de subroutine worden gebruikt. Effectief is dat ook krek hetzelfde, bij het 'pop'pen van een parameter prop je um toch ook in een variabele).
- Heeft geïndexeerde addressering.
- Heeft echter ook maar 1 werkregister.
De geheugenbanken zijn ook maar 256 bytes, dus als je veel nodig hebt ontkom je ook hier niet aan het werken met banken. De instructies daarvoor zijn wat beter herkenbaar dan die bij de 16F omdat het 'banken' een expliciete operand bij de instructes is en er een speciaal 'Bank Select Register' is.

Nog meer alternatieven:
Verdiep je eens in 16 en 32 bits architecturen.
Ik ben enige tijd geleden eens wezen kijken naar de PIC32 serie en de documentatie gedownload. Je schrikt je te pletter van de omvang.
Verder is het een totaal andere architectuur en instructieset en eigenlijk alleen maar te programmeren in C (en daar moet je dan ook weer van houden).
Ik ben er weer mee gestopt.

[Bericht gewijzigd door hadv op (83%)]

Op 17 februari 2012 01:01:24 schreef hadv:
Alternatief: De 18F

Nog een ander hardware alternatief: de enhanced midrange (16F1xxx) chips.

Smijt die pics weg en stap over op een architectuur met softe stacks.
8051 of een ARM Cortex bijvoorbeeld.

Ik heb nooit gesnapt waarom die pics met een hardware stack werken... ( ik snap het wel : door hun gebrekkige memory access. )

Wat nu? Ik weet het niet.

8051 (maar ook beperkt qua stack), ARM, AVR, 'launchpad' achtigen... Alles met een minder beroerde architectuur...

Los daarvan: ik ben niet zo'n fan van subroutines in een ISR. Ik snap dat je er bij een pic niet altijd aan ontkomt (omdat je deels zelf uit moet vogelen waarom je ISR loopt), maar veel andere controllers hebben een interrupt vector per source. Je *weet* dus wie je geschopt heeft.

Als je in assembly blijft schrijven, kan een 8051 prima. Mocht je naar C willen (neem aan dat je Basic net zo min een optie vindt als ik), dan moet je je er even in verdiepen hoe jouw compiler omgaat met parameters en variabelen. 8051 heeft te weinig stack om het stack-based te doen. Vaak is het om het even, soms niet...
Verder is RAM access in assembly wat gecompliceerder op een 8051 (je kunt normaal slechts 1 byte van of naar een register copieren, that's it). Sommige derivaten hebben daar aanvullende instructies voor (die de compiler dan ook weer moet herkennen).

Over het nut van subroutines in intterrupt handlers gaan we het natuurlijk niet hebben (het ligt er helemaal aan hoe lang die subroutines zijn en hoe vaak je ze nodig hebt). En waarom ik 7 niveau's nodig heb in de hoofdlus ook niet. Ik zag geen eenvoudige manier om het meer dan 1 niveau terug te dringen zonder dubbele code te gebruiken of het nog onoverzichtelijke te maken dan het al is. Voor mij zit het overigens logisch in elkaar.

De reden dat ik ooit (ca. 2001) voor de PIC gekozen heb is: flashgeheugen, ICSP, veel ingebouwde periferie, gratis ontwikkelomgeving, laag stroomverbruik. Dat er inmiddels veel meer keuze is, dat weet ik.

De 16F1 serie heeft nog steeds te veel haken en ogen. Lapmiddel op lapmiddel op een verouderde kern, zogezegd. En de keuze is beperkt.

De 18F serie is al een stap hoger dan de 16F serie. Maar nog steeds banken in RAM, 1 werkregister en nog steeds geen echte indexering.

Als ik bij Microchip wil blijven, dan lijkt het me logisch om, ook voor de simpele projekten, een PIC24 te kiezen. Die zijn er ook in "low pin count", hebben een echte 16-bit kern met 16 werkregisters, software stack, geen banken, interrupt vector tabel, vermenigvuldigen, delen en indexed loops in de hardware. En USB OTG.

Bankswitching is een hele vieze truc,om met de verkeerde architectuur toch nog een stapje verder te kunnen.
De prijs is echter veel hoger als je op het eerste gezicht zou denken:Je hebt een virtuoos programmeur nodig,er kunnen heel makkelijk zeer
vieze bugs in sluipen,en het hele spul is niet te porteren naar een ander systeem.
Wil je je nu nog een keertje laten vangen door Microchip? en een ietsepietsie grotere Pic pakken?Met intrinsiek dezelfde probelemn?
Ik snap niet dat Free_electron geen reclame maakt voor de STM8.Perfect voor eenvoudige taken.En we programmeren die
dingen gewoon in C.Het is voor mij toch al enkele jaren geleden dat ik nog maar een blik heb geworpen op de instructie-set en register architectuur van een
microcontroller.Als je in een hogere taal programmeert is dat gewoon totaal irrelevant.

Over het nut van subroutines in intterrupt handlers gaan we het natuurlijk niet hebben (het ligt er helemaal aan hoe lang die subroutines zijn en hoe vaak je ze nodig hebt).

Nou... als ze lang zijn, horen ze niet in een ISR thuis... Snap je punt natuurlijk wel... Maar subroutines in een ISR is iets wat je eigenlijk niet moet willen - al is het maar uit stack oogpunt (het wordt lastig om te bepalen hoe diep je stack kan groeien op die manier). Verder zul je er tegen aan gaan lopen dat subroutines die ook buiten de ISR gebruikt worden re-entrent moeten zijn (en als ze dat niet worden, kun je er beter een macro van maken...). Da's leuk als je al je locals op stack mikt, maar bij bijvoorbeeld een 8051 werkt het doorgaans niet zo. Dus ja, het kan. Je maakt het alleen wel complex...

Als ik bij Microchip wil blijven, dan lijkt het me logisch om, ook voor de simpele projekten, een PIC24 te kiezen. Die zijn er ook in "low pin count", hebben een echte 16-bit kern met 16 werkregisters, software stack, geen banken, interrupt vector tabel, vermenigvuldigen, delen en indexed loops in de hardware. En USB OTG.

Als je toch een andere architectuur moet gaan leren, is iets multi-vendor (8051*, ARM) mi. handiger. Ook in 2001 waren daar (net als voor de AVR) gratis ontwikkeltools voor. Zeker voor de 8051 in grote hoeveelheden. En die zijn er nog steeds. Over laag stroomgebruik: ook daar zijn er (veel) meer van.

*Ik bedoel dan 8051 derivaten. De 'originele' 8051 is wel wat eh... achterhaald. Ook een 8051 heeft bankswitching, maar dan voor je registers. Vreselijk makkelijk voor interrupt routines: andere register bank en niks saven en restoren. Wil je het toch op de hand? Prima, kan ook... Gebruik je het niet.

De 16F1827 (of de 16F1847 met dubbel geheugen) is een pin-compatible replacement voor de 16F88, ik heb er weinig problemen mee. "Lapmiddelen" valt wel mee. Wel veel voordelen, zoals:

- de hogere clocksnelheid.
- lineair ram gebruik zonder banken.
- auto context save bij interrupt.
- interne referentiespanning.
- 16 level stack met overflow melding.
- extended instructionset. (auto inc/dec van de FSR pointer)
- Dubbele indf/fsr registers.

Alhoewel ik met 8-level stack ook nooit problemen heb gehad, en ik heb al heel wat complexe dingen er mee gebouwd... (Alleen de hele oude 16C54 core was irritant met de 2-level stack, dat was wel wat gepuzzel soms.)

Volgens mij kan de OP twee of drie kanten op:

- software aanpassen zodat 't op de F88 past (wellicht niet mogelijk)

- een alternatief kiezen dat zo dicht mogelijk bij de F88 ligt (zodat de bestaande code zoveel mogelijk gebruikt kan worden) maar meer stack entries heeft, een F1xxx is dan de enige mogelijkheid

- een echt andere chip kiezen, dat betekent dat de bestaande assembler code niet makkelijk hergebruikt kan worden. Ik zou dan meteen overstappen naar C en naar een stevige chip, dus geen 8 (8051) of 16-bitter (dsPIC, 430), maar meteen een 32-bitter (ARM, Cortex, MIPS). (Nog niet eens vanwege de verwerkingssnelheid, maar omdat je met 16-bitters binnen afzienbare tijd alweer tegen de beperkingen van 16-bit adressering aanlopen. 64k lijkt veel, maar dat dacht IBM met de eerste PC ook)

Microchip heeft nu al een paar PIC32 chips in 28-pins SDIP, NXP heeft aangekondigd dat er LPC1xxx chips in DIP32 komen (maar ik heb begrepen dat dat dat DIP28-wide is, niet de smalle versie die uChip gebruikt). Dus dan is er zelfs voor hobbyisten weing reden om bij 8 of 16 bitter te blijven steken.

Op 17 februari 2012 08:48:42 schreef free_electron:
Smijt die pics weg en stap over op een architectuur met softe stacks.
8051 of een ARM Cortex bijvoorbeeld.

Ik heb nooit gesnapt waarom die pics met een hardware stack werken... ( ik snap het wel : door hun gebrekkige memory access. )

Zijn die dingen over het algemeen niet veel te lomp / duur voor de toepassing waar pic's voornamelijk voor worden ingezet?

Op 17 februari 2012 10:37:12 schreef M14:
[...]

Zijn die dingen over het algemeen niet veel te lomp / duur voor de toepassing waar pic's voornamelijk voor worden ingezet?

'lomp' lijkt me eerder een qualificatie voor de PIC baseline/midrange architectuur zodra je die moet uitbreiden met bankswitching, code paging etc. (en persoonlijk vind ik de 8051 niet veel minder lomp, en de AVR wat beter maar nogal lomp gedocumenteerd).

'lomp' in de zin dat er geen DIP8 etc. 32-bitters zijn klopt. Voor professionals maakt dat niet uit, die pakken gewoon een SMD behuizing die veel kleiner is dan een DIP8. Maar voor hobbyisten zit hier wel een probleem.

'duur': een LPC1114 (32kb FLASH, 8kb RAM) kost (in mijn shop) ongeveer evenveel als een 16F887 (8k FLASH, 368b RAM). De getallen zijn niet helemaal vergelijkbaar (16-bit instructies voor de LPC, die 8k van de 16F is 8k 14-bit instructies, dus eigenlijk 12k). Maar toch: qua FLASH en RAM bieden de 32-bitters veel en veel meer voor je geld. Ook qua CPU kracht, maar dat is vaak veel minder belangrijk.

Het is wel zo dat er aan de onderkant (kleine chips, bv 6 en 8 pin, heel weining geheugen, bv < 1k) wel 8-bitters zijn maar geen of heel weinig 32-bitters. Maar dat is alleen van belang als de microcontroller een belangrijk deel van de prijs van je product is, en je code zo simpel is dat het veel makkelijker programmeren van een 32-bitter niet belangrijk is.

Aan de andere kant: aan de bovenkant (bv 0.5Mb FLASH, 64kB RAM) zijn er vrijwel geen 8-bitters te vinden. Het is perttig om met de zelfde lijn chips flink ruimte te hebben naar boven.

Het voordeel van PIC's vind ik o.a. dat er pin-compatible MCU's zijn in 8, 16, en 32 bits; je kunt in een bestaand (goed ontworpen) ontwerp dus altijd "doorgroeien", mocht dat nodig zijn...
Daarbij vind ik het overkill om voor bijv. 3 drukknopjes en een display een ARM processor te gebruiken.
En wat al is gezegd, lage kosten van kleine 8 bitters is ook belangrijk...

Op 17 februari 2012 11:17:23 schreef Arco:
Het voordeel van PIC's vind ik o.a. dat er pin-compatible MCU's zijn in 8, 16, en 32 bits; je kunt in een bestaand (goed ontworpen) ontwerp dus altijd "doorgroeien", mocht dat nodig zijn...

Als je engineering kosten voornamelijk de hardware zijn klopt dat, maar vaak is juist de software kostbaar, en dan is bij overstapping niet de pin-compatibiliteit maar de software compatibiliteit van belang. En dan is een 18F en zeker een PIC32 echt heel iets anders dan een midrange (12F, 16F). Dan lijken de ARMs, Cortexes en zelfs PIC32 opeens veel meer op elkaar dan de PIC32 lijkt op een kleinere PIC.

Als je bijvoorbeeld de MikroC/Basic/Pascal compilers gebruikt dan is de software met relatief weinig moeite te porten tussen 8/16/32 bits...

Iedereen schrijft vanuit zijn eigen ervaring en toepassing over microcontrollers. Ikzelf gebruik al PIC controllers vanuit de tijd dat er alleen de PIC16C54XT en de PIC16C55XT bestonden. Het blijven leuke controllers voor weinig geld. Maar voor bepaalde toepassingen zijn ze gewoon niet geschikt. De 16Fxx is leuk voor besturings doeleinden. (I/Os) wil je wat verder pak dan gelijk een 18F en anders een PIC32. Wat Wouter al zegt, de kosten zitten veeal niet in de hardware (paar euro's voor een PIC) maar meer in de vele uren van firmware schrijven.

Welke GSM/GPRS module gebruik je trouwens ? Ken je de SIM900 en 5320E van SIMcom ?

Ik ben het met Arco eens dat het porten van software voor de pic'jes vrij eenvoudig is. De structuur en de gebruikte registers is bij elke variant praktisch het zelfde.

Zelf heb ik niet heel veel ervaring met ARM / Cortex processors. Met lomp bedoel ik dat dit vaak toch al vrij grote dingen zijn (in formaat en functionaliteit) en dat dat vaak niet nodig is. Wanneer je meteen tegen grenzen aanloopt van snelheid, stack, flash, enz, dan moet je je inderdaad afvragen waarom je die keuze van processor hebt gemaakt. Maar dat neemt niet weg dat dergelijke simpele controllers voor veel toepassingen een goede keuze kan zijn.

Overigens moet ik bekennen dat die LPC1114 inderdaad niet duur is vergeleken met veel pic controllers. Maar, om even een voorbeeldje te geven, voor mijn huidige project is zo'n ding zware overkill. Toepassing is een gear indicator, printje is net zo groot als het 7-seg display (19mm x 12.5mm) wat aan de andere kant zit. Daar zit nu een PIC16F688 (tssop14) op. Display wordt aangestuurd vanuit een knopje en een analoge ingang. 1 I/O is ongebruikt. Wat moet je dan met een 32bit ARM oid?

Ik ben niet van plan om voor dit projekt een andere PIC te kiezen; het probleem is opgelost en de firmware is al zo goed als klaar. Maar als dit is afgerond, dan stap ik over op iets anders. Zonder dat het meteen overkill wordt, met behoud van een extreem laag stroomverbruik, met software control van de klokfrequentie.

@plano: idd, een SIMCom SIM900B

Ik heb dit topic aangemaakt om eigenlijk even wat frustratie van me af te schrijven, na letterlijk een paar werkdagen geprobeerd te hebben het probleem te tackelen. Voor mijn werkgever is de verloren tijd geen probleem, er is geen deadline, en hij is blij dat ik altijd met een werkend produkt kom, maar het is voor mij erg frustrerend, en hoe je het ook wendt of keert, het heeft geld gekost.

Op 17 februari 2012 12:25:10 schreef M14:
Wat moet je dan met een 32bit ARM oid?

Snel en makkelijk je software ontwikkelen in C++ met veel hergebruik van objecten :)

Daarnaast komt ARM van ST bv met veel ingebouwde extra's zoals 12Bit ADC / DAC RTC, LCD, CAN enz. Voorbeeldje:

STM8L152C6T6 2,71@mouser

- Low power RTC BCD calendar with alarm interrupt
- Auto-wakeup from Halt w/ periodic interrupt
- LCD: up to 4x28 segments w/ step-up converter
- Memories
32 KB of Flash program memory and 1 Kbyte of data EEPROM with ECC, RWW Flexible write and read protection modes
2 Kbytes of RAM
- DMA
4 channels; supported peripherals: ADC, DAC, SPI, I2C, USART, timers
1 channel for memory-to-memory
- 12-bit DAC with output buffer
- 12-bit ADC up to 1 Msps/25 channels
- T. sensor and internal reference voltage
- 2 Ultralow power comparators
1 with fixed threshold and 1 rail to rail
- Wakeup capability
- Timers
Two 16-bit timers with 2 channels (used as IC, OC, PWM), quadrature encoder
One 16-bit advanced control timer with 3 channels, supporting motor control
One 8-bit timer with 7-bit prescaler
- 2 watchdogs: 1 Window, 1 Independent
- Beeper timer with 1, 2 or 4 kHz frequencies
- Communication interfaces
Synchronous serial interface (SPI)
Fast I2C 400 kHz SMBus and PMBus
USART (ISO 7816 interface and IrDA)
- Up to 41 I/Os, all mappable on interrupt vectors
- Up to 16 capacitive sensing channels supporting touchkey, proximity, linear touch and rotary touch sensors
- Development support
- Fast on-chip programming and non intrusive debugging with SWIM
- Bootloader using USART
- 96-bit unique ID

@TS

Het lijkt erop dat je problemen veroorzaakt worden door het feit dat je zo'n complexe firmware helemaal in ASM schrijft. Als je C kiest met een goede compiler, krijg je minstens zo'n compacte code en je hoeft je opeens geen zorgen meer te maken om stack overflows (krijg je warning voor), bankswitching (verzorgt de compiler) of het aantal (werk) registers. Dat, en je kunt nog altijd de kritische stukken in ASM coden.

Daarbij is C veel leesbaarder en onderhoudsvriendelijker dan ASM. Wellicht niet voor jou of mij, maar wel voor degenen die onze software later mogen onderhouden.

@sdk: Dan ben ik toch benieuwd waar die (C) compiler dat op kan baseren. Een (static) code analyser zou het nog kunnen... Als je source in verschillende files zit (en dat is niet heel ongebruikelijk zeg maar...) dan heeft die compiler helemaal geen weet van hoeveel levels een function gebruikt...

Op 17 februari 2012 14:22:28 schreef EricP:
@sdk: Dan ben ik toch benieuwd waar die (C) compiler dat op kan baseren.

De compilers die dit doen hebben een niet-triviale 'linking' fase, waarin dus veel meer gebeurt dan het aan elkaar rijgen van object code: vaak ook nog inlining en andere optimizations.