David's Engineering Notes
Notes on Electronics and Software: reminders, tips, sources [proton electron]
Apr 19, 2023
Eliminate audio pops when bypass-switching
Feb 18, 2023
Add Arm Cortex Boards to Arduino 1.8.x
For boards not in the Boards Manager
1) go to Preferences to add path of specialty boards (Arduino Feather)
https://learn.adafruit.com/add-boards-arduino-v164/installing-boards
2) Then go to boards manager and search Adafruit, Install SAMxx 32-bit boards (It will take several minutes to load)
instructions: https://learn.adafruit.com/adafruit-feather-m0-express-designed-for-circuit-python-circuitpython/using-with-arduino-ide
Dec 2, 2022
Faster PWM DAC Using Two lower-resolution PWM Signals Added
Faster PWM DAC using parallel lower res PWM.
lower: & 111, higher: >>3 & 111
The Circuit
How to do the math algebraically to down-scale:
Divide and truncate, find remainder
The formulas
Jul 20, 2022
Feb 13, 2022
Gyrator theory and a Working Circuit
But finding an actual circuit with actual values and comments on selecting them is harder to find.
I provide this LTspice model circuit showing a circuit and a way to select reasonable values for an example.
put schematic in github...
added: thorough discussion
Elliott Sound Products |
Jan 7, 2022
Teensyduino Features and Techniques [Part 1]
Excellent combined feature suite
- Small (~ 0.8 x 1.5")
- Fast (96 MHz)
- Runs on 3.3V or 5V, and I/O is 5V tolerant
- Includes a DAC
- 32-bit processor
- Multiple UARTs and USB direct programming
- Supports formatted printing including floats printf() & sprintf()
- real-time clock (RTC), just add 32kHz xtl on bottom
- auto-incrementing timer variable types (elapsedMillis, elapsedMicros) [example...]
Quirks
- 1st time it is programmed, usually requires an extra step (manual btn press to load)
- The button is not a Reset, but rather a program Load. (There is a reset pin on bottom side of the board to which a button may be added)
Particularly useful specialty libraries
- u8g2 (fast lib for nearly all OLED displays; includes multiple fonts)
- TeensyStepper (very fast pulse rates, synchronous across multiple motors)
- SoftPWM (allows PWM on any digital pin)
- FastLed & its fast math routines (8 & 16-bit sin, cos, random)
Dec 21, 2021
Arduino IDE: setting tab indent to another value
Change default tab setting to four (4) spaces in IDE (applies to version 1.6.10 and later.)
Steps:
Exit Arduino IDE. (otherwise the closing of application will overwrite preferences file.)
Edit preferences.txt on two lines:
Create new file:
- formatter.conf
in your Arduino directory (in the same location as preferences.txt)
in windows:
C:\Program Files (x86)\Arduino\lib = C:\Users\{USRNAME}\AppData\Local\Arduino15on mac: it's /Users/{USRNAME}/Library/Arduino15/
Add this one line:
indent=spaces=4
editor.tabs.expand=true
editor.tabs.size=4
Save and exit.
Then save and relaunch.
Tabbing and auto-formatting (^t) will indent consistently.
References:
Information source: (https://github.com/arduino/Arduino/issues/5012)
Aug 26, 2021
Python 3: run a script, string and number formatting
Python Language techniques
To run a python script from the terminal
1) create python script “cow.py”2) Execute with python3 cow.py
Reference: https://howchoo.com/python/run-python-terminal
Python 3 string and number formatting: f-strings
- Use the operator “f” in a print()
- enclose variables in braces
- Add number format modifiers after the variable, preceded by a “:”
print(f'{x:5.2f}\t{y:6.2f}\t\t{z:8.2f}
f-strings: formatting large numbers with commas
Commas are often needed when formatting large numbers. The following shows the use of
commas when numbers are aligned.f-strings: formatting large numbers with commas
number = 1000000
# print with comma separators
print(f'The number:, 1000000 {number:,.2f}')
# formatted with commas and right-aligned
print(f'The number, 1000000,
in a width of 15 {number:>15,.2f}')
Also do... Example: The output of this code snippet is:?? missingTBD
References:https://cis.bentley.edu/sandbox/wp-content/uploads/Documentation-on-f-strings.pdf
Aug 25, 2021
Arduino: Creating asynchronous timed events auto-increment variables, the convenient elapsedMillis() function
Aug 24, 2021
R-C Snubber: How to Calculate Values
R-C Snubber
Diode and Zener+Diode Damping
For power switching circuits
The graph shows the trade-off between amount of damping and amount of power loss.
Note: To insert a formatted equation, see this LaTeX online equation editor.
Aug 8, 2021
Measuring Fast and Slow Pulses on the Teensyduino Microcontroller
addendum T3.2, T3.6, usec conversion for fast pulse measurement
Jul 23, 2021
Assessing Reliability, Statistical Failure rates
MTBF: calculate series and parallel
Example: If there are two power supplies in a system, with the 2nd for redundancy, what does that do to the resulting statistical failure rate?
With each having an MTBF of 100 hrs, that's 1% chance of failure in 100 hrs.
But both is 0.01 x 0.01 = 0.01% or 10,000 hrs
See this detailed explanation below.
Oct 3, 2020
Use a Voltage Detector to Create a Fast, Clean Input to your Microcontroller
The basic function you're looking for is a comparator; something that looks at a change (that may be slow) and makes a quick change at a set threshold. Furthermore, most designs have some amount of hysteresis to avoid rapid on-off switching.
You can solve it by fixing the power supply or forcing the MCU to wait until the power is good.
The problem of a poor startup on circuits especially microcontrollers is a long-standing one. There is a family of inexpensive 3-terminal devices specifically for this problem from most companies. They are usually used to hold the Reset line of the processor in the Reset state until the voltage has reached stability at the desired voltage. They will often include a time-delay as well after the threshold before releasing the reset line to assure a clean start. They are called "Power On Reset" or "IC Supervisors" or "Voltage Detector" or simply "PMIC" and they are just a comparator in a transistor-looking package. For example: some devices at Digikey.
You'll see that you select the device to match the polarity of the reset, and the desired fixed voltage to switch.
Similar functions are built into many voltage regulators: it's the input for "under-voltage lockout."
If you have full control of the design you could use either of these methods to control the regulator or the MCU on the board. However, if you want to add this "after market" to an existing system, and if you can access the reset line directly, then connect drive it with one of these.
Use the Voltage Detector as your comparator, but use its output to drive the ENable of a load switch IC; this is basically a mosfet transistor optimized for pass-through function. An example of one is an ADP1290ACBZ-R7 from analog devices. The input of the load switch is the slow supply; the output is a clean switch at V_threshold of ~ 2.8 - 3.0V.
[todo: pair with a suitable voltage divider and show circuit...]
Mar 15, 2020
solid-state relays AC, DC, and reed relays
*** VO2223a DC to AC (opto-coupled triac) 0.5A, Vishay
CPC1020N 30V SPST 4-Pin SOP OptoMOS® Relay. IXYS
leadless transistor pkg
PMBT3904M,315 TRANS NPN 40V 0.2A SOT883, NXP Semiconductor
reed relays can be a good choice; wide voltage; AC or DC output 0.5ms response.
Coto or similar items
Dec 28, 2019
eeprom read/write functions
Read and write
one, four-byte variables and character strings
to eeprom in Arduino C++
Create functions for a consistent interface for single and multi-byte variable rd/wr to non-volatile ram using the EEPROM library.
// single byte read uint8_t eepromReadByte(uint16_t addr) { return EEPROM.read(addr); } // single byte write void eepromWriteByte(uint16_t addr, uint8_t data) { EEPROM.update(addr,data); // "update" only writes if byte is different } // four-byte read uint32_t eepromReadInt32(uint16_t addr) { uint32_t data = 0; byte b; for (uint8_t i = 0; i < 4; i++) { b = EEPROM.read(addr); data |= 0x000000FF & (b << 4*i); data |= b; } return data; } // four-byte write void eepromWriteInt32(uint16_t addr, uint32_t data) { for (uint8_t i = 0; i < 4; i++) { uint8_t aByte = 0x000000FF & (data >> 4*i); EEPROM.update(addr+i,aByte); } } // write character array void eepromWriteChars(uint16_t addr, char str[16], byte num_chars) { for (byte i=0; i<num_chars; i++) { EEPROM.update(addr+i,str[i]); } }
Usage:
eepromWriteByte(ADDR_COUNTDOWN_SECONDS,g_secords);
Initialize EEprom memory:
Test if memory has been written to;if yes, read values; else write default values
// update eeprom values int init_marker = 42; if (eepromReadByte(ADDR_EEPROM_INIT) == init_marker) { // some unique value readCountdownIntervalFromEEprom(); } else { // first-time init eepromWriteByte(ADDR_EEPROM_INIT, init_marker); writeCountdownIntervalToEEprom(); // write defaults }
Nov 13, 2019
function to increment/decrement and cycle through a range
Cycle through values in C++/Arduino
Increment or decrement by an integer value, (normally +1 or -1) but cycle between min and max constraints. Test code at gitHub
EX: dec by -1 4 3 2 1 4 3 2 1
inc by +2 -4 -2 0 2 -4 -2 0 2
int16_t cycleIncDec(int16_t x, int16_t dir, int16_t xmin, int16_t xmax) {
// inc/dec with constrained range
// supplied xmax must be greater than xmin
x += dir;
if (x > xmax) x = xmin;
else if (x < xmin) x = xmax;
return x;
}
Sep 24, 2019
modify formatting settings in Visual Studio Code
To modify code formatting settings in vsc,
search C_Cpp.clang_format_fallbackStyle
add the follwing to User tab
Change the default
from Visual Studio
to {BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0, SpacesBeforeTrailingComments: 8}
I found this info at:
https://stackoverflow.com/questions/46111834/format-curly-braces-on-same-line-in-c-vscode
and more at
https://medium.com/@zamhuang/vscode-how-to-customize-c-s-coding-style-in-vscode-ad16d87e93bf
Sep 7, 2019
getting filename and path of current program [arduino]
Capture and extract the filename and path for the current file within an Arduino program.
There are a few variables available at compile time including compile time and date. The filename is also available and supplied with its full path. The code below shows a way to separate them into String variables.Code:
/* get the file name and path of this program */
const char this_file[] PROGMEM = __FILE__; // provided by system
const String file_and_path = String(this_file); // convert to a String
int n = file_and_path.length();
int i = file_and_path.lastIndexOf("\\") + 1; // escaped backslash for Windows paths
String filename = file_and_path.substring(i,n); // from last '\' to end
String filepath = file_and_path.substring(0,i); // from begin to last '\'
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.println(file_and_path);
Serial.println(filepath);
Serial.println(filename);
}
void loop() {
}
Output:
C:\Users\david1\Desktop\test\test.ino
C:\Users\david1\Desktop\test\
test.ino
Jul 26, 2019
mapFloat(): Arduino's map() function extended to allow float variables
A function to extend range mapping to float/double variables.
Feb 13, 2019
Using hobbytronics USB Flash Drive breakout board with Arduino
To get the device to write to a file from demo code (first example at btm of pg) seemed to work ok.
To send a command and read back responses, some hours of testing and several modifications were needed for my configuration to work.
Things to check first:
- Is the baud rate to the USB Drive Host board set to default of 9600 to start?
- Is the Tx of the board connected to the Rx of the MCU and vice versa?
- Are command strings terminated with a Serial1.write(13) or '\r' ?
The example uses softwareSerial library. I used a hardware port, preferred if available. (Serial1 on Teensyduino 3.x)
If no response comes from your command, you'll need additional delay. I had to add time after the command, and a time between each character sent. In the example code, a while(!Serial.available()) is used to wait until the first character starts.
While troubleshooting, I connected directly to the board from a TTL-to-USB interface to TeraTerm terminal program. Once the first 3 items above were correct, Commands (such as DATE, CD, DIR) worked just fine.
By adding:
- delay(100) after each sent command
- adding a delay(1) before each character read in the while loop,
... sprintf(mystring,"$TIME \r"); mySerial.write(mystring); delay(100); // *** getFromFlash(); ... } void getFromFlash() { char c; // Hang out here while(!mySerial.available()); // Wait for data to be returned // loop waiting for a character for each line separately // Read and display contents of line returned while (mySerial.available() > 0) { c = mySerial.read(); delay(1); // *** Serial.write(c); } if (c != '\r' && c != '\n') { // Serial.write(13); Serial.write(10); } }
Other notes
asdf
Aug 30, 2017
When can adding noise increase signal resolution?
- If there is time to average multiple samples
- If the signal is quiet relative to ADC resolution
- If there is a way to generate and combine a noise source with signal before the ADC sampling.
22.4 22.4 22.5 22.4 22.3 22.4 22.4 22.4
22 22 22 22 22 22 22 22
Clearly averaging would not improve the value because the actual values are always between 1 LSB (either 22 or 23 in this case).
22.4 22.4 22.5 22.4 22.3 22.4 22.4 22.4
+ 0.0 1.0 0.0 0.0 1.0 0.0 1.0 0.0
-----------------------------------------------------
22.4 23.4 22.5 22.4 23.3 22.4 23.4 22.4
22 23 22 22 22 23 23 23 avg = 22.5
So eight measurements will have some 22 and some 23, with the ratio close to the fractional value. In this example I only used values of 0 or 1, but a wider range of values between and shaping the noise distribution can further improve the estimate.The smoothed value (purple) of the noisy samples (green) is closer to the actual value (blue). |
In practice, any random or pseudorandom source will work. 4x oversampling is enough to get a benefit, and 8 or 10 is quite good. If the signal is noisy more than 1-2 LSB (as it usually is), then there is no benefit to adding noise. Just average as you would normally to get better effective resolution.
Aug 29, 2017
The Sigmoid or Logistic Function
See https://en.wikipedia.org/wiki/Logistic_function
Aug 23, 2017
Markdown editor uses split-screen web page for real-time rendering
Web-based editor is correct and displays instantly.
https://jbt.github.io/markdown-editor/
References this comprehensive suite of code syntax highlighting languages and styles https://highlightjs.org/
Lag filter for control systems, calculating the filtering constant k
This is the same equation as that for an exponential smoothing filter which is a highly useful and low-computation smoothing technique similar to, but generally better than, an N-point average. A starting point for k is 0.5, which is roughly equal to a 4-point average.]
The formula for a first order lag filter is fairly simple:
new_filtered_value = k * raw_sensor_value + (1 - k) * old_filtered_value
The "magic" is determining an approprate value for k.
Calculate k
To calculate k, enter Tr, Ts and Frac from above into the following equation:k = 1 - eln(1 - Frac) * Ts / TrFor details, see http://my.execpc.com/~steidl/robotics/first_order_lag_filter.html
Aug 17, 2017
additional high quality random numbers xoroshiro128+
Aug 9, 2017
transistor noise generator circuit with lots of gain
Aug 2, 2017
Bayesian weighted probabilities
He provides software links as well.
Another look on wikipedia for Bayes' Theorem. Thomas Bayes worked this out around 1740.
Jun 22, 2017
output a data stream to screen and a file using tee
./a.out | tee > logfile.txtIt is not smooth, as the terminal is buffering data. To change that, use
unbuffer ./a.out | tee > logfile.txtTo use unbuffer, you must install the "expect" package*
References
https://stackoverflow.com/questions/11337041/force-line-buffering-of-stdout-when-piping-to-tee *to get it on Mac unix, the package installer recommended is homebrew.
1) install homebrew if you don't have it.
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew search expect
brew install expect
Add comma separators to large numbers
Use:
put addCommas(11456789)
Returns:
11,456,789
Long example:
Dec 11, 2016
Arduino 3 & 5 point running median
Example shows random data stream with real-time running median filtering.
Snippet (Full current code on github at https://github.com/davidsmith99/median )
double median3( double a0, double a1, double a2 ) {
swap(&a1, &a2); // swaps values if arg1 > arg2
swap(&a0, &a2);
swap(&a0, &a1);
return a1; // median value
}
//using in a loop
void loop() {
// generate random data with outliers to observe median filtering
// use 3 most recent values
// drop val_prev2 value and update the latest value
fval_prev2 = fval_prev1;
fval_prev1 = fval_new;
fval_new = 0.99 * (10 + random(-2, 8) + (random(0, 4) == 0) * 4 * (random(0, 5))); // small variation plus occasional spikes
double fmedian = median3(fval_prev2, fval_prev1, fval_new);
Serial.print(fval_new); Serial.print("\t");
Serial.print(fmedian); Serial.print("\n");
delay(200);
}
Other related links:
http://playground.arduino.cc/Main/RunningMedianreference on function overloading c++
http://www.programmingsimplified.com/cpp/source-code/cpp-function-overloading-example-program
Nov 21, 2016
Scan for I2C Devices on Bus [arduino function]
Here's a much shorter version of this as a function call (no args, no return value). Maintained on github here.
void i2cScan() {
Serial.println ("\ni2cScan...\n");
static int count = 0;
Wire.begin();
for (int i = 8; i < 120; i++)
{
Wire.beginTransmission(i); // probe this i2c address
if (Wire.endTransmission() == 0)
{
Serial.print (" device at: 0x" + String(i, HEX) + " [" + String(i) + "] \n"); count++;
delay (1);
}
}
Serial.print("\nTotal devices: " + String(count) + "\n");
}
Updated a diagnostic script to be a function with optional outputs [Arduino]
n = i2cScan(0); // prints nothing; returns 0|1 for successful read of at least one device
n = i2cScan(1); // prints address of successfully read devices (arg of 2 prints result of every address)
output:
I2C device at 0x19 25
I2C device at 0x1E 30
I2C device at 0x3C 60
I2C device at 0x40 64
I2C device at 0x6B 107
I2C device at 0x77 119
6 devices found.
code:
// -------------------------------------------------- int i2cScan(int printFlag) { int nDevices = 0; int error = 0; for (int address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { if (printFlag > 0) { Serial.print("I2C device at 0x"); if (address < 0x10) Serial.print("0"); // leading zero Serial.print(address, HEX); Serial.print("\t "); Serial.println(address); // dec } nDevices++; } else if (error > 0 && error != 99) { // 2 = no device if (printFlag == 2) { Serial.print(" Error:"); Serial.print(error); Serial.print(" at 0x"); if (address < 0x10) Serial.print("0"); // leading zero Serial.print(address, HEX); Serial.print("\t "); Serial.println(address); // dec } } } if (nDevices == 0) { if (printFlag > 0) Serial.println("No devices found.\n"); } else { if (printFlag > 0) { Serial.print(nDevices); Serial.println(" devices found.\n"); } } return (nDevices == 0); // 0 for no errors and at least one device; }
More info about i2c at http://www.gammon.com.au/i2c
Oct 31, 2016
printBits() prints formatted binary numbers, Arduino code
When diagnosing embedded code, it's often convenient to see the individual bits of a variable. There is no formatting function for this in C. Wiring does have an option to format as BIN, but I wanted to see leading zeros and separate long numbers with spaces.
Here is a routine to print an integer variable in a formatted binary format including leading 0s.
Would work with C/C++ if print command is changed appropriately.
// prints N-bit integer in this form: 0000 0000 0000 0000 // works for 4 - 32 bits // accepts signed numbers void printBits(long int n) { byte numBits = 16; // 2^numBits must be big enough to include the number n char b; char c = ' '; // delimiter character for (byte i = 0; i < numBits; i++) { // shift 1 and mask to identify each bit value b = (n & (1 << (numBits - 1 - i))) > 0 ? '1' : '0'; // slightly faster to print chars than ints (saves conversion) Serial.print(b); if (i < (numBits - 1) && ((numBits-i - 1) % 4 == 0 )) Serial.print(c); // print a separator at every 4 bits } }
Example usage with the number of bits set to 16.
printBits(0x51f); 0000 0101 0001 1111
printBits(-1); 1111 1111 1111 1111
int k = 65;
printBits(k); 0000 0000 0100 0001
Example with the number of bits set to 10 and delimiter set to a period.
printBits(0x2A5); 10.1010.0101
A nicely implemented conversion calculator is here. http://www.binaryconvert.com/
Additional solutions are at stackoverflow.com
Aug 1, 2016
Consistent system for software versioning [SemVer]
Semver.org Summary 2.0.0
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
Mar 15, 2016
Lua language is basis for a nice parser in Arduino
A script language to extend other languages, in particular C and its derivatives.
A sensible grammar and syntax.
Re-discovered while looking into string parsing. Nick Gammon has made a nice extension library for arduino using a lua syntax.
Feb 21, 2016
More precise frequency measurement, pulse measurement
arduino.datamaster2003.com/f-measurements.htm
See also TimerOne library by Paul S.
https://github.com/PaulStoffregen/TimerOne