uSupply Firmware Released - Page 1
Forum section: electronics / projects

author: EEVblog
author_rank: Unknown
timestamp: May 26, 2020, 01:15:01 am
content: I've now released the uSupply firmware for those interested.https://gitlab.com/eevblog/usupply-firmwarehttps://gitlab.com/eevblog/usupply-libraryhttps://gitlab.com/eevblog/usupply-usb

author: uer166
author_rank: Super Contributor
timestamp: May 26, 2020, 05:11:42 am
content: Is it just my lack of experience/exposure to it or is C++ harder to read/understand than C in the embedded context?

author: EEVblog
author_rank: Unknown
timestamp: May 26, 2020, 07:29:35 am
content: Quote from: uer166 on May 26, 2020, 05:11:42 amTo me it looks like Klingon. So yeah, harder. But mostly depends on how you write it.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: May 26, 2020, 07:58:23 am
content: Code:const char * volatile current{[]() -> const char *{I'm pretty sure it is Klingon. Live long and prosper.

author: Dave
author_rank: Super Contributor
timestamp: May 26, 2020, 10:36:26 am
content: Very professionally organized repositories.Can't say I'm a big fan of C++ for embedded, but it does have its place in safety non-critical applications.

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 26, 2020, 02:27:55 pm
content: Quote from: NivagSwerdna on May 26, 2020, 07:58:23 amYeah. Some C++ constructs are really cryptic.I've taken a look at the source code. Overall, it looks pretty well written. I won't comment on the use of C++ (we have done this a lot already), but I admit that, although the whole thing looks very well written, it's still a bit hard to grasp for anyone not having developed it IMHO.Another thing that strikes me is the amount of source code for all this. I don't have all the features of the uSupply in mind, but it sure looks like there is *a lot* of code, and I'd venture that it could have been done with a lot less code. In that respect, having used C++ doesn't seem like a gain in development time IMHO.Still - hats off to Dave (2). I have rarely seen code that was that well written and laid out (not judging functionality or possible bugs of course, it's just a first look.)

author: nuclearcat
author_rank: Unknown
timestamp: May 26, 2020, 06:46:31 pm
content: I think when device is released and if it will be affordable, we might see competition who can (IF CAN!) write better code(and hopefully giving away to Dave)

author: NivagSwerdna
author_rank: Super Contributor
timestamp: May 26, 2020, 08:59:47 pm
content: Quote from: nuclearcat on May 26, 2020, 06:46:31 pmProbably but I've never really understood working for free, seems like a poor business model.

author: ataradov
author_rank: Super Contributor
timestamp: May 26, 2020, 09:52:07 pm
content: You do not work for free, you work for yourself. If you think a better firmware will be useful to you, you work on it. Releasing it to others is just a side effect. It is mostly driven by the fact that it is very hard to monetize things like this.And yes, this C++ heavy code is very hard to read, and the whole functionality could be implemented in a much-much smaller code.

author: thm_w
author_rank: Super Contributor
timestamp: May 26, 2020, 10:38:36 pm
content: These are the compiler flags, I believe:QuoteSo it should be unnecessary to tag a bunch of functions with noexcept right?Code:void Enabled( bool enable_1, bool enable_2 ) noexceptQuote from: uer166 on May 26, 2020, 05:11:42 amIts not necessarily all C++, its how this code was written using a number of advanced C++ features.

author: EEVblog
author_rank: Unknown
timestamp: May 26, 2020, 11:14:55 pm
content: Quote from: ataradov on May 26, 2020, 09:52:07 pmNot a comparison because the features aren't even remotely the same, but for those interested, previous versions of my uSupply written by me are 389 lines and 479 lines for two of the design variants.That's everything, including comments, UI code, control code etc.Not sure I'd like to guess how many lines this version of the uSupply would have taken me in "Dave C", but yes, it would been vastly different to the way David writes his code. I just let him do it the way he wanted, we have vastly different styles. But he writes games engines in his spare time for fun, and I wouldn't know C++ if it bit me on the arse.

author: EEVblog
author_rank: Unknown
timestamp: May 26, 2020, 11:21:57 pm
content: For kicks, this is "Dave C" for my last uSupply USB prototype, the entire program:Code:/* ****************************************uSuppyUSB FirmwareVersion 1.0Last Edit: 8/9/12Written in: AVR GCC C under AVR Studio 6Written by: David L. JonesCopyright(C)2012 David L. Jones[url=http://www.eevblog.com]www.eevblog.comNOTES:- Written for an ATmega88A target on Rev 1 uSupplyUSB HardwareRevision notes1.0 - First prototype version******************************************* */#define F_CPU8000000//clock frequency 8MHz#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>#include <avr/eeprom.h>#include <string.h>#include <stdio.h>//definitions#define version1#define TRUE 1#define FALSE 0#define CURRbutton(PINB & 1<<PB7)//CURRENT button#define SETbutton(PINB & 1<<PB6)//SET button#define bit_get(p,m) ((p) & (m))#define bit_set(p,m) ((p) |= (m))#define bit_clear(p,m) ((p) &= ~(m))//#define POWPIN_HIGHPORTC.PINC4=1//#define POWPIN_HIGHbit_set(PORTC, PINC4);#define POWPIN_HIGHPORTC|=0b00010000#define POWPIN_LOWbit_clear(PORTC, PINC4);#define DIG1ON PORTB=0xE//Switch ON the first digit, current display#define DIG2ON PORTB=0xD//Switch ON the second digit, current display#define DIG3ON PORTB=0xB//Switch ON the third digit, current display#define DIGITSOFF PORTB=0xF//Switch OFF all digits, current display#define DIG1VON PORTB=0xFB//Switch ON the first digit, voltage display#define DIG2VON PORTB=0xF7//Switch ON the second digit, voltage display#define DIG3VON PORTB=0xEF//Switch ON the third digit, voltage display#define DIGITSVOFF PORTB=0xFF//Switch OFF all digits, current display#define SEGPORTPORTD// the LED display digits are on PORTD// define the two rotary encoder input pins#define PHASE_A(PINC & 1<<PC5)#define PHASE_B(PINC & 1<<PC6)#define ADCcomplete(ADCSRA & (1<<ADSC))//TRUE if ADC is complete//#define ADCcomplete(ADCSRA & 1<<ADIE)//TRUE if ADC is complete#define setADCIE(ADCSRA|=1<<ADIE)//global variablesunsigned char DIGIT_NUM;int SET_VOLTAGE;//the set output voltage in mVint SET_CURRENT;//the set output current limit mAint READ_VOLTAGE;//the measured output voltage in mVint READ_CURRENT;//the measured current output in mAint READ_VOLTAGE_ARRAY;//array for averagesint READ_CURRENT_ARRAY;//array for averagesint READ_VOLTAGE_AVERAGE;//the measured output voltage in mVint READ_CURRENT_AVERAGE;//the measured current output in mAunsigned char digit;//the number of the currently displayed LED digitunsigned char CCmode;//TRUE if in Constant Curent modeint VoltageSETcount;//counter for temp display of the set voltage as the knob is turned.int SETbuttonCount;//counter for the time the SET button has been pressedint DPblinkCount;//counter for the constant current mode decimal point blink modechar blink;const unsigned char digitdata={0x3F,0x6,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F,0};// 7 segment digit display datavolatile int8_t enc_delta;// -128 ... 127static int8_t last;static int8_t knobcount;//*****************************************************************//saves the current voltage and current figures to EEPROMvoid SaveEEPROM(void){cli();//disable interrupts so it doesn't corrupt the write process//eeprom_write_word(0,SET_VOLTAGE);//eeprom_write_word(2,SET_CURRENT);sei();//enable interrupts againreturn;}//*****************************************************************//loads the stored voltage and current data from the EEPROMvoid LoadEEPROM(void){cli();//SET_VOLTAGE=eeprom_read_word(0);//SET_CURRENT=eeprom_read_word(2);sei();return;}//*****************************************************************//displays a number on the selected 7seg display// If DP is TRUE the associated Decimal Point turns ONvoid Disp7SEG(unsigned char digit, unsigned char num, unsigned char DP){unsigned char temp;DIGITSOFF;//disable the entire LED displayDIGITSVOFF;//if ((CCmode!=0) && (digit<4)) DP=1;//force decimal point on for current display in CCmodeif (num>9) num=10;// if unknown digit then display a blank digittemp=digitdata;if (DP!=0) temp=temp|128;// turn on decimal point if requestedSEGPORT=temp;//output the display segmentsswitch(digit){case 1:DIG1ON; break;case 2:DIG2ON; break;case 3:DIG3ON; break;case 4:DIG1VON; break;case 5:DIG2VON; break;case 6:DIG3VON; break;}//leave the digit displayed until the next call, so we can continue processing and we get persistence of vision.return;}//*****************************************************************// Updates the voltage and current PWM outputsvoid UpdateOutput(void){unsigned long PWMvalue;PWMvalue=((unsigned long)SET_VOLTAGE*1000)/47695;//(12210mV full scale / 256 bits)if (PWMvalue>255) PWMvalue=255;//overflow trap, we don't want any undesirable wrapOCR1A=PWMvalue;//set the output VOLTAGEPWMvalue=((unsigned long)SET_CURRENT*1000)/1078;//0-255 = 0-275mV/if (PWMvalue>255) PWMvalue=255;//overflow trap, we don't want any undesirable wrapOCR1B=PWMvalue;//set the output CURRENTreturn;}//*****************************************************************// reads the voltage and current values from the ADC and updates the global variablesvoid ReadValues(void){unsigned long value;unsigned long total;unsigned char c,temp;if (CURRbutton){//measure VOLTAGEADMUX=0b00000001;//select ADC1 input and 1.1V reference, right adjustedvalue=ADCL;//get the upper 8 bit resultvalue=value+(ADCH*256);//get the lower 8 bit result and add it on.value=value*1074;//convert to microvolts for 1.1V referencevalue=value/1000;//convert back to millivoltsREAD_VOLTAGE=value*12;//multiply for the resistor dividerfor(c=0;c<39;c++)//update the moving average arrayREAD_VOLTAGE_ARRAY=READ_VOLTAGE_ARRAY[c+1];READ_VOLTAGE_ARRAY=READ_VOLTAGE;total=0;for(c=0;c<40;c++)total=total+READ_VOLTAGE_ARRAY;READ_VOLTAGE_AVERAGE=total/40;}else{//measure CURRENTtotal=0;ADMUX=0;//select ADC0 input and 1.1V reference, right adjustedvalue=ADCL;//get the upper 2 bit resultvalue=value+(ADCH*256);//get the lower 8 bit result and add it on.value=value*10740;//convert to microvolts for 1.1V referencevalue=value/10000;//convert back to mV (/1000)//the final value is now in mA*10READ_CURRENT=value;for(c=0;c<39;c++)//update the moving average value arrayREAD_CURRENT_ARRAY=READ_CURRENT_ARRAY[c+1];READ_CURRENT_ARRAY=READ_CURRENT;total=0;for(c=0;c<40;c++)total=total+READ_CURRENT_ARRAY;READ_CURRENT_AVERAGE=total/40;}return;}//*****************************************************************// Checks to see if the user has turned the rotary encoder knobvoid CheckKnob(void){if (enc_delta==1){knobcount++;VoltageSETcount=0;}if (enc_delta==-1){knobcount--;VoltageSETcount=0;}enc_delta=0;if (knobcount>3){if (CURRbutton)//adjust the VOLTAGE{SET_VOLTAGE=SET_VOLTAGE-50;if (SET_VOLTAGE<0) SET_VOLTAGE=0;}else//adjust the CURRENT{SET_CURRENT=SET_CURRENT-1;if (SET_CURRENT<0) SET_CURRENT=0;}UpdateOutput();//update the output voltage/current on the terminalsknobcount=0;}if (knobcount<-3){if (CURRbutton)//adjust the VOLTAGE{SET_VOLTAGE=SET_VOLTAGE+50;if (SET_VOLTAGE>12200) SET_VOLTAGE=12200;}else//adjust the CURRENT{SET_CURRENT=SET_CURRENT+1;if (SET_CURRENT>300) SET_CURRENT=300;}UpdateOutput();//update the output voltage/current on the terminalsknobcount=0;}}//*****************************************************************// Interrupt Service Routine// This ISR has several functions. It is based on TIMER0// 1) Updates the 7 segment display at regular intervals// (This display only one digit every interrupt, digits get cycled through each ISR pass)// 2) Reads and updates the status of the rotary encoder knob// 3) Ticks over a counter to hold the display in a set state for a certain periodISR(TIMER0_OVF_vect){unsigned int temp;unsigned char dig1, dig2, dig3, dig4, dig5, dig6, dp1, dp2, dp3;int8_t state, diff, CURRset;cli();//disable interruptsVoltageSETcount++;if (VoltageSETcount>=500) VoltageSETcount=500;if (!SETbutton) SETbuttonCount++; else SETbuttonCount=0;if (CCmode){if (blink) DPblinkCount++; else DPblinkCount--;if (DPblinkCount>100) blink=FALSE;if (DPblinkCount<=0) blink=TRUE;}dp1=0;//turn all decimal points OFFdp2=0;dp3=0;CURRset=0;//assume we are displaying the READ current and not the SET currentif (digit==4||digit==5||digit==6)//display the VOLATGE display digits{if (SETbutton) temp=READ_VOLTAGE_AVERAGE; else temp=SET_VOLTAGE;if (VoltageSETcount<500)//force display of the SET voltage or current if the knob has been turned within the time limit{if (CURRbutton) temp=SET_VOLTAGE;else{temp=SET_CURRENT;CURRset=TRUE;}}if (temp>9999)//check for voltages 10V or greater, we have to switch the decimal point and calcs{dig4=temp/10000;temp=temp-(dig4*10000);dig5=temp/1000;temp=temp-(dig5*1000);dig6=temp/100;dp2=TRUE;//decimal point for 99.9}else{dig4=temp/1000;temp=temp-(dig4*1000);dig5=temp/100;temp=temp-(dig5*100);dig6=temp/10;dp1=TRUE;}//decimal point for 9.99}else// ELSE display the current display digits{if (SETbutton) temp=READ_CURRENT_AVERAGE; else temp=SET_CURRENT;if (!CURRset && SETbutton) dp2=TRUE;//turn on decimal point for 99.9mA display if we are displaying the READ current//otherwise display the SET current with 1mA resolutionas 999mAif (temp>=999)//if current is >99.9mA{dig1=temp/1000;temp=temp-(dig1*1000);dig2=temp/100;temp=temp-(dig2*100);dig3=temp/10;}else{dig1=temp/100;temp=temp-(dig1*100);dig2=temp/10;temp=temp-(dig2*10);dig3=temp;}if (CCmode)//if in constant current mode then blink the decimal point{if (blink){dp1=FALSE;dp2=FALSE;dp3=FALSE;}}}//display the currently selected digit//this digit will stay on until the next ISR loop, giving persistence of visionif (digit==1) Disp7SEG(1,dig1,dp1);if (digit==2) Disp7SEG(2,dig2,dp2);if (digit==3) Disp7SEG(3,dig3,dp3);if (digit==4) Disp7SEG(4,dig4,dp1);if (digit==5) Disp7SEG(5,dig5,dp2);if (digit==6) Disp7SEG(6,dig6,dp3);digit++;//display the next digit next time through the ISR loopif (digit>6) digit=1;//read the rotary encoder knobstate = 0;if( PHASE_A ) state = 3;if( PHASE_B ) state ^= 1;// convert gray to binarydiff = last - state;// difference valueif( diff & 1){// bit 0 = value (1)last = state;// store new as next lastenc_delta += (diff & 2) - 1;// result will be +1 for positive direction and -1 for negative direction}ReadValues();//read the ADC valuessei();//enable interrupts again}//*****************************************************************int main(void){unsigned char c,d,average;unsigned char keyspeed, keycount;DDRB =0b00000111;//PB0, PB1, PB2, PB3, PB4 are OUTPUTS, all others INPUTSPORTB=0b11111000;//enable pull-ups on all PORTB pins except PB1 and PB2 which are outputsDDRC =0b00111000;//PORTC are all INPUTS, except for 3 LED digit outputsPORTC=0b11000111;//enable pull-ups on only upper 3 pins PORTC pinsDDRD =0b11111110;//PORTD are all OUTPUTSPORTD=0;MCUCR=0;//Enable pin pull-ups and Disable Sleep BOD stuff.POWPIN_HIGH;//Latch the power ON//PORTC=0xFF;// this must be done BEFORE the PWM is turned on to ensure we DON'T OVERSHOOT at power on!LoadEEPROM(); //restore the saved voltage and current settingsif (SET_VOLTAGE>12200)SET_VOLTAGE=12200;//do some out of bounds checkingif (SET_VOLTAGE<50)SET_VOLTAGE=50;if (SET_CURRENT>100)SET_CURRENT=100;if (SET_CURRENT<1)SET_CURRENT=1;//set up TIMER0 used for the display updating (165Hz rate per digit)TCCR0A=0x3;//use the /64 prescaler for clock sourceTIFR0=0;TCNT0=0x0;TIMSK0=1;//enable the TIMER0 interrupt//set up PWM in TIMER1TCCR1A=0b10100001;//clear on compare match, SET at TOP for both PWM output pins. 8bit FAST PWM mode.TCCR1B=0b00001001;//matchig 8bit fast PWM mode settingTCNT1=0x3FE;UpdateOutput();//set the output voltage and current//set up ADCPRR=0;//make sure all periphers are turned ONADCSRB=0;//free running mode, manual triggerDIDR0=3;//diable digital input on ADC0 and ADC1 pinsADCSRA |= (1 << ADATE);//ADMUX |= (1 << ADLAR);//left align ADC resultADCSRA |= (1 << ADEN);//enable the ADCADCSRA |= (1 << ADSC);//start conversionADCSRA |= (1 << ADPS2);//prescaler = 128ADCSRA |= (1 << ADPS1);//prescaler = 128//ADCSRA |= (1 << ADPS0);//prescaler = 128//set up the user control knob interrupt//PCMSK1=32;//enable knob pin change interrupt//PCICR=2;//ebale the PCIE1 pin change interruptDisp7SEG(3,version,0);//display version number at power on_delay_ms(2000);digit=1;average=0;keyspeed=0;keycount=0;VoltageSETcount=0;SETbuttonCount=0;DPblinkCount=0;ReadValues();sei();// enable interrupts (turns on display and functions)while(TRUE){if ((SET_CURRENT*10) < (READ_CURRENT_AVERAGE+1)) CCmode=TRUE; else CCmode=FALSE;//check to see if we are in Constant Current ModeCheckKnob();//check if the user has turned the knobif (SETbuttonCount>=1500)//check to see if the SET button has been pressed for 3 seconds{SETbuttonCount=0;SaveEEPROM();cli();Disp7SEG(1,5,0);_delay_ms(1000);sei();}}}

author: uer166
author_rank: Super Contributor
timestamp: May 26, 2020, 11:53:46 pm
content: Even in the tiny forum window I can figure out what's going on.. This must be hardware vs. software engineering thinking ways.

author: Dave
author_rank: Super Contributor
timestamp: May 27, 2020, 12:53:04 am
content: As soon as software becomes slightly more complex, you need to start splitting it in logical units, which you put into separate files. A well written software should not have files that stretch for more than a couple of hundred lines. There are of course always exceptions to this rule, but in general, one shouldn't have to scroll around and search for a particular part of code.Next thing is abstraction. Just tossing register names around all over the place is very poor form. At the very least they should be macroed away with descriptive names.Preferably, hardware abstraction should be done in a separate module altogether, so you never actually fiddle with registers directly in the application portion. By making code modular, porting code to a new platform becomes very easy. Want to use a new microcontroller? No problem, just replace/modify the hardware abstraction module and you're set.Good code usually doesn't even need comments, because the names of the functions and variables themselves are descriptive enough to make it clear what something is doing.

author: nuclearcat
author_rank: Unknown
timestamp: May 27, 2020, 12:55:55 am
content: Quote from: NivagSwerdna on May 26, 2020, 08:59:47 pmYou can gain a lot from writing free code.)Community recognition. When you contribute to opensource, your potential employer will probably get an positive impression about you even before he looks at your CV.In some cases, if you are contractor - you may be hired, since such portfolio is the best portfolio.)Honing your skills and you might get free beta-testing and free review by professionals, including (probably) Dave. It is unlikely that you will have enough money to make Dave interested to touch and look to your proprietary code otherwise.)Competition. Its FUN to be best!And not only about gaining something. Altruism is good for humanity. Starting from the fact that the forum(software running it, OS, etc) we are talking in - exists, because many programmers once gifted the world pieces of their code.

author: nuclearcat
author_rank: Unknown
timestamp: May 27, 2020, 01:05:10 am
content: Quote from: Dave on May 27, 2020, 12:53:04 amAnonymous function (refered as authored by klingon) probably overkill for embedded and exactly opposite "of easy to understand code".And whole fact returning pointer to *char by anonymous function might be fine on PC, but ehm, i think questionable in embedded.But thats IMHO, i might be wrong.I generally try to be careful and conservative with C++ features in embedded, you never know which function will make your code "suddenly overweight" or will start using "under the hood" dynamic memory allocation/reentrant functions/etc and guarantee you problems.But it’s best to prove that, if i can write better code. Sure if i will be alive by the time uSupply will be released for sales.

author: splin
author_rank: Frequent Contributor
timestamp: May 27, 2020, 01:41:12 am
content: Quote from: Dave on May 27, 2020, 12:53:04 amint Check_DMA_NotAboutToAcessSPI_CMD_RegisterWhilstUART1_TX_CompleteFlagSet_ToAvoidLockup_DescribedInErrata3.16.7(void);

author: ataradov
author_rank: Super Contributor
timestamp: May 27, 2020, 01:45:04 am
content: There is obviously a need for things like erratas and minor notes. There is no need to write poems, or a typical copy-paste with boiler-plate description of each parameter.If the code implements some non-standard algorithm, the comments may help too. Especially on a way some constants are derived and stuff like that.Peripheral drivers rarely need comments. In most cases the first thing I do if I really need to understand some code, I remove all the comments.

author: ehughes
author_rank: Frequent Contributor
timestamp: May 27, 2020, 02:08:13 am
content: I have been wanting to experiment with cmake and I noticed that Dave had a nice little template for getting started.Some of my longer term projects could benefit from a more (easily) configurable build system.

author: EEVblog
author_rank: Unknown
timestamp: May 27, 2020, 03:27:00 am
content: Quote from: nuclearcat on May 27, 2020, 12:55:55 amI had someone charge most of my uWatch code to include playing chess and other cool stuff, and he even write a manual for it:All off his own bat, because he just wanted to, and bragging rights on the hpmusuem forum tool I guess. A true calculator nerd.http://www.taswegian.com/uwatch/uWatch.pdf

author: EEVblog
author_rank: Unknown
timestamp: May 27, 2020, 04:47:25 am
content: Quote from: nuclearcat on May 27, 2020, 01:05:10 amThe other thing is that David kept finding issues in the C++ compiler (and STM target), as in bugs or quirks that prevented the program from working, and in one case resulted in weeks worth of project delay until the compiler could be patched.So yeah, the further you push the obscurities of the compiler, the more potential issues you would have for various reasons.

author: nuclearcat
author_rank: Unknown
timestamp: May 27, 2020, 05:25:25 am
content: Quote from: EEVblog on May 27, 2020, 04:47:25 amThis is most common problem for those programmers who take for granted fancy features of c++17/etc and worked with them mostly on non-embedded targets.I hit my hands when i try to use "on autopilot" convenient std::vector(for example) in embedded, after got used to it hour ago on some linux software.Nevertheless, the basic conveniences of C++ in the form of classes, constructors and destructors are reliable, thanks to the army of arduino testers (gcc/g++ under hood). And they make life much simpler and code more readable even for 8-bit AVR.

author: EEVblog
author_rank: Unknown
timestamp: May 27, 2020, 06:47:39 am
content: Quote from: nuclearcat on May 27, 2020, 05:25:25 amYes, I don't think David had issue with them on his PC stuff.

author: hans
author_rank: Super Contributor
timestamp: May 27, 2020, 08:54:26 am
content: Quote from: nuclearcat on May 27, 2020, 01:05:10 amAnonymous functions are sometimes useful, but often not in embedded.C++ templates for embeddedareuseful, but also to certain degree. I like the tidiness of the codebase, it seems well maintained and structured. However, I've seen a few cases where I don't think I would have used a template, as the code size/speed gain is probably very small or absent (assuming the optimizer is turned on sufficiently).Being careful with mechanic/function selection of C++ is a good point. You need to be aware of how the STL functions are implemented, and which are suitable for use on embedded, and also at which portions of the code, or are better left for unit tests (e.g. if the library uses dynamic memory allocation such as std::vector vs std:array). However, I think there are many language features/gems that are too good to leave untouched, for example templates and fast reusage of existing code using classes.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: May 27, 2020, 09:09:33 am
content: Quote from: nuclearcat on May 27, 2020, 12:55:55 amI actually contribute to at least three open source projects.... but I still think it is a rubbish business model.[I'm probably jaded by having spent decades contracting]

author: Jeroen3
author_rank: Super Contributor
timestamp: May 27, 2020, 10:06:33 am
content: Quote from: uer166 on May 26, 2020, 11:53:46 pmScript hackers vs SOLID developers.https://nl.wikipedia.org/wiki/SOLID

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 27, 2020, 02:01:41 pm
content: Quote from: EEVblog on May 27, 2020, 04:47:25 amThat's one more reason the choice of using C++ in this project, at least the way Dave used it, was probably not a good idea. Days of delay for tools issues - that's OK. But weeks? You were probably not in a big hurry at the time, and wanted to give him maximum autonomy, but as a manager, you should probably have made a couple decisions to limit useless delays.Again, I admire the clarity and elegance of his code, but I still question the choices and architecture. A bit too bloated for my taste.Now to be clear, OTOH I find Dave (Jones) coding style pragmatic, but a bit too simplistic and not the most reusable or most easy to maintain. My take would be somewhere in between.

author: nuclearcat
author_rank: Unknown
timestamp: May 27, 2020, 06:10:54 pm
content: Quote from: SiliconWizard on May 27, 2020, 02:01:41 pmFor me it is pretty typical AVR Studio code, "It just works(tm)", similar to code in Atmel datasheets.(And half of code is unavoidable registers voodoo).

author: MiroS
author_rank: Regular Contributor
timestamp: May 27, 2020, 06:55:29 pm
content: Quote from: Dave on May 27, 2020, 12:53:04 amIf you think than please take this as home assigementhttps://ptolemy.berkeley.edu/projects/embedded/pubs/downloads/spice/spice2.ibm.tar.gzand come back where is more clarity and complexity

author: Dave
author_rank: Super Contributor
timestamp: May 27, 2020, 10:14:58 pm
content: Quote from: nuclearcat on May 27, 2020, 01:05:10 amThere are some aspects of C++ that I think would be useful for embedded platforms, like operator overloading, constructors and destructors, default arguments in functions. Other than that...I'm not terribly fond of anonymous functions, either.Quote from: MiroS on May 27, 2020, 06:55:29 pmYou linked in an ancient project coded in FORTRAN (I only know this because I actually searched for the SPICE wiki). I can't possibly comment on a programming language which I don't know and have never used. If the language does allow for splitting the code into multiple files, then 18k lines in a single file is in fact terrible coding practice.

author: Dave
author_rank: Super Contributor
timestamp: May 27, 2020, 11:14:11 pm
content: Quote from: splin on May 27, 2020, 01:41:12 amI get that you're trying to poke fun at me, but I'd like to take this opportunity to expand on my statement.I'm going to borrow part of the 'Dave C' example pasted above and to demonstrate how I'd split something of the sort into a separate file to make it a separate logical unit.Here is his boxcar averaging code for measuring voltage:Code:for(c=0;c<39;c++)//update the moving average arrayREAD_VOLTAGE_ARRAY=READ_VOLTAGE_ARRAY[c+1];READ_VOLTAGE_ARRAY=READ_VOLTAGE;total=0;for(c=0;c<40;c++)total=total+READ_VOLTAGE_ARRAY;READ_VOLTAGE_AVERAGE=total/40;I split this filter into a separate filter.c file with its respective filter.h header.Code:/* filter.h *//* The header file of the filter module, which should be #included at the top of main.c */#ifndef FILTER_H#define FILTER_H#include <stdint.h>#define FILT_BOXCAR_LEN 40typedef struct{uint8_t index;uint16_t sum;uint16_t buffer;uint16_t avg;} filt_boxcar_t;extern void Filt_Boxcar_Init(filt_boxcar_t *filt);extern uint16_t Filt_Boxcar_Sample(filt_boxcar_t *filt, uint16_t input);#endif /* FILTER_H */Code:/* filter.c *//* This is where different sorts of filters are implemented */#include "filter.h"void Filt_Boxcar_Init(filt_boxcar_t *filt){uint8_t n;for(n=0; n<FILT_BOXCAR_LEN; n++){filt->buffer = 0;}filt->index = 0;filt->sum = 0;filt->avg = 0;}uint16_t Filt_Boxcar_Sample(filt_boxcar_t *filt, uint16_t input){filt->sum -= filt->buffer[filt->index];filt->sum += input;filt->buffer[filt->index] = input;filt->index++;if(filt->index >= FILT_BOXCAR_LEN){filt->index = 0;}filt->avg = filt->sum / FILT_BOXCAR_LEN;return filt->avg;}So to use this in Dave's project:Code:/* top of file */#include "filter.h"/* variables definition */filt_boxcar_t filter_volt;filt_boxcar_t filter_curr;/* initialization routine */Filt_Boxcar_Init(&filter_volt);Filt_Boxcar_Init(&filter_curr);/* places in the code where the ADC samples are captured and need filtering*//* see the original code we attempted to replace */READ_VOLTAGE_AVERAGE = Filt_Boxcar_Sample(&filter_volt, READ_VOLTAGE);/* a bit lower */READ_CURRENT_AVERAGE = Filt_Boxcar_Sample(&filter_curr, READ_CURRENT);/* note: I'm not a fan of using all caps for variables, as those are usually reserved for macros, but it is what it is */As you can see, the same filter function is called for filtering both values. Not only that, the same filter module can have multiple filters implemented inside and all of them can then be elegantly used wherever they're needed in different sections of code. Making things modular may not be strictly necessary in small pieces of code, like just testing some proof of concept with a couple hundred lines, but it is absolutely crucial in larger projects.

author: jbb
author_rank: Super Contributor
timestamp: May 28, 2020, 12:34:51 am
content: Oh no, now I'm doing it...... and to extend that to hypothetical C++, it gets quite tidy.Code:/* top of file */#include "filter.hpp"/* filter objects definition (self-initialising) */filt_boxcar_t filter_volt;filt_boxcar_t filter_curr;/* places in the code where the ADC samples are captured and need filtering*//* see the original code we attempted to replace */READ_VOLTAGE_AVERAGE = filter_volt.update(READ_VOLTAGE);/* a bit lower */READ_CURRENT_AVERAGE = filter_curr.update(READ_CURRENT);In the end, this will compile to much the same thing as the C option*. The filter update semantics quite nicely tie the filter data storage to the filter update function. The initialisation is done implicitly by the constructor which is often pleasant but sometimes a pain to control precisely. I've had good results with this sort of thing for signal processing stuff like filters, PI controllers etc.However, if we use advanced features like exceptions and class polymorphism the resource usage (RAM, ROM, time) can suddenly go up. Maybe you really need those features and are willing to pay for them. Or maybe youdon't, and are wondering why the binary size has exploded.I've never done much with templates, but I understand that some compilers (once upon a time, a someone told my mate's cousin at the pub) might not quite understand which templates you were using, and simply generate the template code forall possible types. Which makes your binary explode. Hopefully newer compilers aren't that stupid.* If we were being anal retentive, we could call to the fact that the C Filt_Boxcar_Sample() isn't checking for null pointers, and adding run time checks would consume resources. The compiler handles the pointer for the C++ version so you don't need a run time check.

author: EEVblog
author_rank: Unknown
timestamp: May 28, 2020, 05:43:13 am
content: Quote from: SiliconWizard on May 27, 2020, 02:01:41 pmSuch a decision is really only possible in hindsight.Each small problem is always presented/appears as being the "last hurdle". Then you have another one, and another one, and another one, and before you know it you are too far down the process to change direction. Such a change in direction would have meant rewriting most of it in the "DaveC" way, a method that David is not familiar with and would actually hate to do. It's not good to piss off your engineering employees and make them do something they don't want to do, and effectively saying "you way is shit, do it this way because I say so", it's better to give them autonomy to get the job done using methods they are familiar with and think will do the best job.Also, because I'm no expert in C++ and the tools David used to do all this, I had to essentially trust him and his judgement, and the end result is entirely what David wanted and the way he produces code.With hindsight now, yes I would have insisted that he use the plain vanilla ST tools and regular C, and set better code targets. Just look at the video we did just setting up the tools and environment he used, it's very complicated and one that was ultimately not needed for such a relatively small embedded project. But it's what he was familiar with being an uber code nerd.

author: EEVblog
author_rank: Unknown
timestamp: May 28, 2020, 05:47:53 am
content: Quote from: Dave on May 27, 2020, 11:14:11 pmYeah I do do that, but it's neither here nor there with a project like this. I don'tneeddifferent filters, I don'tneedcode re-use for other projects, I just needed7 lines of codeto get a simple job done.

author: EEVblog
author_rank: Unknown
timestamp: May 28, 2020, 05:54:32 am
content: Quote from: SiliconWizard on May 27, 2020, 02:01:41 pmFor a bigger project I would have used multiple files and split things up more.In fact I sometimes do this as a 2nd pass once a project gets bigger. I'm not a fan of putting in a lot of modular coding work for a project what I knew would only need a few hundred lines of code to get a working prototype, and maybe a few hundred more to refine a final product.

author: Dave
author_rank: Super Contributor
timestamp: May 28, 2020, 07:19:00 am
content: Quote from: EEVblog on May 28, 2020, 05:47:53 amRight, exactly what I said at the end of my post.Quote from: Dave on May 27, 2020, 11:14:11 pm

author: Jeroen3
author_rank: Super Contributor
timestamp: May 28, 2020, 10:30:28 am
content: Well, the thing is that developers write code to handle change of requirements. So from programmers point of view I think there are three major objectives:1. The code must pass the tests (aka the requirements).2. The code must allow change of requirements at low cost.3. The code must be maintainable, other people need to be able to read it.To try and make this easy we have invented Object Oriented Programming anddesign patternsto use to conform to the solid rules.What we call "DaveC" here only passes requirement 1. And requirement 3 for the first few weeks. After 2 iterations of rule 2 and it's too big. Read up on "why software fails".Now the problem here is that many embedded software developers are also electrical engineers used to making hardware. Changes to hardware are always expensive. So changes are less common.Also the embedded software is often named firmware. Firm isn't hard, but also not soft.It's in between.It's perfectly fine to write a small bit of code that makes a chip do a simple job and to never change it again. Your quarts watch for example. There DaveC is perfectly acceptable if you can test it.It's another thing to write a reasonably chunk of code doing a simple job fow now with the idea to later improve upon it. Your Apple Watch.This is in my opintion the biggest weak spot of the embedded world. Many people who write code for embedded are not career developers. And many career developers do not know how to write code that works on embedded. With the above shown "figh" about the "best code".However, compared to the target audience, I can see the concern here. The uSupply with this architecture isn't a project average joe who bought an arduino can get on with. But does it need to be?(3 is unfortunately largely forgotten by many people)I'm currently developing in Qt C++. And it's hard, as embedded engineer. With Qt you are forced to comply to SOLID and design patterns. Trying "DaveC" fails after about 5 features.

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 28, 2020, 02:24:07 pm
content: Quote from: EEVblog on May 28, 2020, 05:43:13 amBelieve me, I know exactly what you're saying here! That actually defines a technical manager's job pretty well. We're confronted with that all the time. "Last hurdle"? Yes, I've heard that too so many times!And with experience as a manager, you learn how to spot that and anticipate. Correctly monitoring the project will help not waiting until it's too late to change directions.It may not have meant rewriting everything from scratch either! I'm pretty sure using a simpler subset of C++ (which gets back to other discussions on C++ for embedded targets) would have been enough to get out of the rut without Dave 2 having to change all his code base or switch to pure C. Not using the problematic C++ constructs would have been enough, and probably not *that* difficult to do. He may have "wasted" one week instead of several without moving forward. Now his insisting on still using them while it made him waste weeks, that wasn't good. Hopefully, he's learned a few things along the way!That's IME one of the hardest parts of tech management. Sometimes you need to make the decisions for others, even when your engineers are swearing they know what they're doing and basically ask you to leave them alone. Interestingly, if you don't make the required decisions (even when they are hard to make), your engineers (at least some of them) will end up resenting you! As a manager, you're expected to make decisions and give them guidance - which is hard to do, because right when you do that, they will usually try their best to argue you're being wrong. Just sharing my 2 cents of experience here.

author: VEGETA
author_rank: Super Contributor
timestamp: May 28, 2020, 10:10:43 pm
content: what about the hardware circuit? < million dollar question for +10 years xD

author: uer166
author_rank: Super Contributor
timestamp: May 29, 2020, 02:00:03 am
content: Quote from: VEGETA on May 28, 2020, 10:10:43 pmDon't care for the USB whatever, but Ireallywould like to see the video about the design of that planar transformer and the actual converter itself in detail.

author: Gonzy78
author_rank: Contributor
timestamp: May 29, 2020, 10:10:20 am
content: Dear Dave,Will it be open hardware ?I am quite interested you detail the input USB-C part of the schematic. This is neat stuff. USB BC V1.2 is way much easier than type C PD ...About what we have seen so far, the design looks interesting.I didn't read all about on the forum, is there an official topic ?I can't see any battery to fit inside. A supply with embbeded battery would be a killer. You can take your gadget in the meeting room, or on your desk without taking the heavy supply from the lab and wires ...If you need, I made a custom size lipo this year with my team. I know how to do this, manufacturers, import, certifications, quality control, ... Plenty of work but worth every cents.The dream would be with banana and usb output.The usb output would be killer feature, it would able negociate with the sink. You choose what kind of charger/protocol you want test with your new fashion gadget.Maybe you didn't thought about that. It's a free ideaI hope see that in the shop soon. It's on my wishlist for santa. We all hope more videos about your work on this project.Thanks for reading the comments Dave

author: MiroS
author_rank: Regular Contributor
timestamp: May 29, 2020, 10:14:05 am
content: Quote from: Dave on May 27, 2020, 10:14:58 pmIt is not matter of used language. That FORTRAN pice of code is still in use and formed the foundation for modern electronics, so there is nothing to comment on this from your end, but there is a lot to learn from for everyone who is going to write the code - how to write it to let others use it , modify , improve , document , enapsculate , reuse , maintain ...

author: diyaudio
author_rank: Frequent Contributor
timestamp: May 29, 2020, 12:13:16 pm
content: Dave and David thank you for contributing to the open source initiative, I learned a few things I didn't know about CMAkE could do like the integration with visual studio code which is my Editor/IDE of choice.

author: wizard69
author_rank: Super Contributor
timestamp: May 29, 2020, 05:34:06 pm
content: Quote from: NivagSwerdna on May 26, 2020, 07:58:23 amOne of the reasons for my love/hate of C++ is this very cryptic syntax if you are not involved in C++ full time. We need something better than C but what that might be is unknown at the moment. I actually think Apples Swift could have a lot of potential once it is fully fledged out as a language.The problem with C++ is that you have to mentally parse every statement instead of simply reading it. I can write something in Python and read tte code 5 years latter, write something in C++ and you may spend a considerable amount of time just figuring out what is going on even if it was written 5 weeks ago. Of course with discipline C++ can be made idiomatic but that means leaving modern features behind.

author: wizard69
author_rank: Super Contributor
timestamp: May 29, 2020, 05:46:51 pm
content: Quote from: EEVblog on May 26, 2020, 11:14:55 pmI think most people here are pointing out the general difficulty one can have in reading somebody else's C++ code. Dave may have a good solution here but for a third party reading the code it might take hours to understand the structure. That is just one of the issues with C++, but I do wonder how long it would take Dave to grasp this code 5 years down the road with no refresh in between.In the end the only thing the code needs to do is work correctly. The good code organization is a positive indicator here so I'm not worried. Frankly I'm waiting for you guys to ship.

author: wizard69
author_rank: Super Contributor
timestamp: May 29, 2020, 05:56:07 pm
content: Quote from: ataradov on May 27, 2020, 01:45:04 amIf you get no value out of the comments then they really don't server a purpose. However that doesn't mean comments shouldn't be used. The trick is to use comments in a way that facilitates understanding the code. In many ways comments should be like foot notes in a formal paper that clarify or offer reference for the programmer to further explore. Of course formal papers are not perfect but if programmers could grasp when more information is need we could go a long way to useful and not excessive comments.

author: Dave
author_rank: Super Contributor
timestamp: May 30, 2020, 08:54:31 pm
content: Quote from: MiroS on May 29, 2020, 10:14:05 amThat spice2 project is most certainly not a good example how to write code. 18k lines in a single document is ridiculous.Have a look atspice3. It's written in C and the whole project consists of dozens of documents instead of a handful of massive ones.

author: splin
author_rank: Frequent Contributor
timestamp: June 02, 2020, 01:34:56 am
content: Quote from: Dave on May 27, 2020, 11:14:11 pmI really wasn't - I was pointing out that there are times when you need comments. I'm really not a fan of the 'comments are not needed because the code is self explanatory' school. Code only shows you what it does - not what it supposed to do, why it was written the way it is, the restrictions and limitations arising from the implementation etc. The latter are often related to scaling issues –eg. it will work for small problem sets but will fail badly if you use on medium to large sets.Note: code example clipped slightly for brevity'QuotePlease don't take this personally as I understand you were just providing a quick, rather than a fully engineered example, but I hated your solution! But note that: this is as it applies to this specific case - robust, optimized library solutions for common problems can avoid developers continually reinventing the wheel with their own unique, new buggy versions. They are often a very good idea.But your example doesn't, being inflexible, fragile and worse, produces the wrong results. It doesn't help me as someone in the position of writing Dave's original code - it makes my life harder! In the following scenario consider the case where I am working in a large company on a somewhat larger project than the usupply, using the same type of filter.First up: Dave's original solution is simple, probably took a few minutes to write, does exactly what he needed, and importantly, because he wrote it he almost certainly understood its behaviour and limitations and would have had a good idea about the speed and memory footprint. It may not be the fastest but who cares if the processor only spends 95% of its time idling instead of 95.5%?OTOH, when management decrees that you (ie. the other Dave, who proposed the above code) will be responsible for providing filter solutions for all development teams and those must be used unless there is a strong justification for not doing so, I lose control of that part of my code.Seeing that I have already implemented a pair of moving average filters, you (the filter team) base your official version on that - because it clearly meets my requirements, and I'm told, in line with best practices in the company's software development processes that I have to use those instead of my likely buggy version as I'm not the resident 'filter expert'.With luck you will have provided some documentation and/or example code to show how it's used along with a custom header file configuration tool - to prevent any none-greybeards editing 'buffer length' macro definitions in the header files because the coding/development standards demand that only level 7 and above consulting language experts can do so as it is well known that macros are responsible for 43.7% of all bugs.So now I have to spend time locating all the above as well as the header files and code, ensuring they are all at the right revision level by using the code and document repository management tools to request access. With luck, within a couple of days it will be authorised and my access rights updated to read-only. Helpfully, henceforth, I will be sent regular emails to inform me about the latest spelling correction revisions to the user documentation.To use your solution, although I'm told it's thoroughly tested and ‘Purified’ (is that still a thing these days?), that was on the filter team's 64 bit machines - it hasn't been built or tested for the 8-bit micro target environment I am using. Thus I'm forced to read through your code to ensure that it does what I need with no pitfalls or unexpected side-effects. But your code, with the extra indirections necessary to make it reusable is a bit harder to read and takes me almost as long as writing the original code.At this point I'm not happy. The official moving average filter, unlike mine, uses an extra 5 bytes, possibly 6 with padding, of my precious, *very* limited static RAM resource for each instantiation. I had planned to add several new few short filters to my code, but the extra overhead has killed that plan so I'll have to see if we can work-around the noise problems some other way.This improvement was obviously done as a speed optimization which would be ‘much, much better-er’. Except that I don't have a speed problem I have a memory problem! Worse, the filter team decided it would be a good idea to include an additional structure element ‘avg’ to keep a copy of the last computed average value just in case you forgot to save your own copy and should you happen to need it again. I don't need it but in the many requirements review meetings I was requested to attend, other teams - who almost certainly will never require any sort of filter - agreed "it might be useful". They went on to demand various kitchen sink parts also be included but fortunately there was no consensus on whether it should be taps, drainer or waste fittings so luckily we managed to avoid the worst.On a second look you realise the filter doesn’t actually work as it was clearly only ever tested with small input values. My version (as did Dave’s of EEVBlog fame) used a long type for the sum variable whereas the improved one only uses a uint16_t. Perhaps they were in touch with their 'embedded side' after all, trying to save memory and CPU cycles. Of course, although my voltage and current samples come from a 10 bit ADC and the sum of 40 of them will actually fit into a uint16_t, my code rescales the input values which means both the Voltage and Current filters can overflow. That's not good but even worse is that my original version, had it also used an uint16_t for the sum, it would at least have recovered after 40 more samples provided the input values weren’t too large thus providing some sort of work-around to the customer. The new improved version is so fragile that once the sum value becomes corrupted it will never recover.So now I've got to either change my code or fight my way through the change control process to get the filter fixed, though their opening stance is that the code was self explanatory - it was quite clear that input values > 65536/40 were not acceptable, and there were no comments to the contrary. You should have scaled your input accordingly. Eventually they concede that it could be improved (but they were never wrong) and agree to release an update in due course.[WARNING - even more contrived section - skip if you have a life]You get the update which now accounts for the fact that the maximum value of the sum variable depends on the length of the filter as well as the amplitude of the input samples. Because there is no maximum filter length limitation in the API documentation (that would have required a series of meetings with the users to agree a change to the API) the filter team team decided to implement dynamic sizing for ultimate flexibility. Now the sum is initially a 16 bit value (for efficiency on 8 or 16 bit targets) but when it gets close to the limit it switches to a 32 bit type. Best of both! What's not to like - efficient and adaptable?As a bonus the APi now allows you to specify the overload behaviour - either take the hit with the 32-bit accumulator or switch to saturating logic to retain the speed and code size advantage of a 16-bit accumulator. Naturally you have to pay with a few more dozen of your precious static RAM bytes but clearly it's worth it, Look how shiny those saturation values are...[/WARNING - even more contrived section - skip if you have a life]So we are all done... please? Ermm no. you don't get away that easily; you see I get to the point where, as I suspected, the current channel turns out to be noisier than hoped so it requires a longer filter. The buffer length is currently defined using a macro in the header file; problem is that in the interest of code safety, as per MISRA rules, dynamic memory allocation isn’t allowed. The user will now have to explicitly provide statically allocated filter buffers. The necessary API changes mean new rounds of change requests but you win the case eventually because they can see the whites of your eyes and your bared canines.Now the filter construction in my code requires:Code:#define VOLTAGE_ FILT_BOXCAR_LEN 40#define CURRENT_ FILT_BOXCAR_LEN 70filt_boxcar_t filter_volt;filt_boxcar_t filter_curr;uint16_t voltage_buffer;uint16_t current_buffer;Filt_Boxcar_Init(&filter_volt, &voltage_buffer, VOLTAGE_ FILT_BOXCAR_LEN);Filt_Boxcar_Init(&filter_curr, &current_buffer, CURRENT_ FILT_BOXCAR_LEN);Unfortunately the filter structures now have to include the filter length and pointers to the actual buffer. It will all crash and burn spectacularly if I get it slightly wrong but that's a small price to pay for the dramatic improvements from the provision of rugged and reliable standard library implementations. What an idiot I was thinking I could write my own filter in 10 minutes.For those who haven't given up the will to live by this point I'll spare you the issues arising from the design change requiring the need to update the Current filter within an interrupt routine. Suffice it to say that it isn't pretty. And the solution involved writing my own obscurated filter in assembler code labelled 'Definately_not_a_moving_average_filter', cunningly disguised as a delay loop to match hardware timings. It should work as almost nobody else knows this processor’s assembler code. I have to hope that smart-arse, up and coming, looking to make a name for himself Rodgers isn’t on the code review team....And worst of all. because I clearly have some limited skills in coding filter I have now been enrolled into the filter team design review meetings....QuoteThanks. You turned 10 minutes work into 8 weeks of fruitless arguing with management and the filter team that their ’elegant solution’ was a POS and totally unsuitable for my needs. The extra static RAM had to come from the stack allocation so fingers crossed that an I2C interrupt never occurs during a remote configuration mode change in debug mode.Quote from: Dave on May 28, 2020, 07:19:00 amBut the ‘elegant solution’ is just as rubbish and unnecessary in a 500K LOC project as in a simple test program. Yes we know you were illustrating the concept of reusability with a simple example but it is definitely not always ‘absolutely crucial’ no matter how big the project. Even complex functions that look like they should be provided in a library shouldn't always - especially in embedded, details matter, often performance related. There are always costs as well as advantages.Please don't claim that I'm advocating that every team writes all their own code and reuse is bad. Its horses for courses. Now if your talking polyphasing decimator FIR implementations I probably don’t want to write my own. In C or assembler...

author: nuclearcat
author_rank: Unknown
timestamp: June 02, 2020, 06:49:27 am
content: Management, MISRA, few bytes of precious SRAM?Did i missed something or we are talking about PoC code for uSupply (low cost power supply) made by <2 person (because eventually Dave2 not working on it anymore)?

author: splin
author_rank: Frequent Contributor
timestamp: June 02, 2020, 11:37:04 am
content: Quote from: nuclearcat on June 02, 2020, 06:49:27 amI was referring to a hypothetical example of a large embedded development, written in C, that happened to be using the same type of filter to illustrate some of the issues that can arise from a well meant attempt to 'improve' the project by providing library functions for commonly used functions.

author: Dave
author_rank: Super Contributor
timestamp: June 02, 2020, 07:22:47 pm
content: Quote from: splin on June 02, 2020, 01:34:56 amI won't take offence at constructive criticism, don't worry.The example I provided was made to demonstrate the principle of parting code out into separate logical units and show that it adds clarity to the code. The idea behind it is that as you read through a piece of code, it's easy to get a general understanding of what is going on."Okay, I'm inside an ADC conversion complete interrupt, so first I read the sample from the ADC registers, then it gets filtered and then passed into a scaling function that returns SI units. Then I compare that to some parameters and do xyz."Having the ADC register gymnastics, filters and scaling functions in separate files and functions, with descriptive names, makes the signal flow clear even without adding comments to the code. Nobody is stopping you from adding comments, but the code is understandable without them.On the other hand, reading through code that has everything bundled together inside the ISR, requires more effort to understand what's going on."I'm inside an ADC conversion complete interrupt, then I'm reading register ADCH, shifting that up and then adding the value from register ADCL. All of the elements in this array are being shifted and here I'm putting the newly assembled number to the beginning. Now I'm summing all of the elements inside the array,..."Again, the latter is perfectly fine for a blob of code that is meant as a proof of concept, but you'd rather not have that when multiple people are working on the same code.Your criticisms of the filter code itself are valid. I haven't taken the time to even try and compile that, I just quickly typed something up to show an example.Quote from: splin on June 02, 2020, 01:34:56 amI'd disagree. Splitting things into functional units is not optional if you're talking about half a million lines of code, the code would be impossible to maintain otherwise. A hefty amount of documentation would be needed to boot.Quote from: splin on June 02, 2020, 01:34:56 amIt's always like that, no way around it. If meeting some strict timings requires being wary of every single CPU clock cycle, then subroutine calls would of course be undesirable. My statements obviously don't apply to those cases.

author: wizard69
author_rank: Super Contributor
timestamp: June 03, 2020, 01:07:36 am
content: This discussion is very interesting with respect to software, but the real question is when does this guy ship? I mean hardware here, I really like the idea of this little supply.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: June 04, 2020, 08:57:37 am
content: Quote from: wizard69 on June 03, 2020, 01:07:36 amExactly. Without some sample hardware nobody is going to start tweaking the firmware (for fun or profit).PSIs there a PC side app too? One that sends SCPI commands? I would be interested in seeing how that was done because I need to build something similar myself and am not sure where to start!

author: prasimix
author_rank: Unknown
timestamp: June 04, 2020, 10:50:16 am
content: Quote from: NivagSwerdna on June 04, 2020, 08:57:37 amIf you are interested in a PC side app, perhaps you can take a look at:https://www.eevblog.com/forum/testgear/eez-studio-for-accessing-your-(scpi)-instruments/

author: NivagSwerdna
author_rank: Super Contributor
timestamp: June 04, 2020, 11:05:47 am
content: Quote from: prasimix on June 04, 2020, 10:50:16 amI'm interested in building a cross platform driving GUI to control my gadget (it's not actually SCPI). Thanks for the link though... looks like you used Electron which isn't something I have tried... might check that out.