Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Category: Software
General-purpose computers doing something specific
While I’m thinking about instrument screen shots, this is the script for my Hewlett-Packard 8591E Spectrum Analyzer.
You’ll need C-Kermit, ImageMagick, and hp2xx for this one, too.
The cable must cross-connect RTS/CTS for hardware flow control.
Set the spectrum analyzer to
print-to-plotter
19200 b/s (limited by USB-to-RS-232 converter)
One plot per page
Turning menus off doesn’t seem to have any effect on screen captures from the serial port, so the script crops off that part of the image.
Copy-n-paste the following text into a file (gethp8591), make it executable (chmod u+x gethp8591), and run it with a file name (./gethp8591 test).
Unlike the (well, my) 54602 ‘scope, the 8591 responds to serial commands just like the Fine Manual says. So before you run this script, make sure the screen shows what you want.
#!/usr/bin/kermit +
# Fetches screen shot from HP8591E spectrum analyzer
# Presumes it's set up for plotter output...
# Converts HPGL to PNG image
set modem none
set line /dev/ttyUSB0
set speed 19200
set flow rts/cts
set carrier-watch off
# Make sure we have a param
if not defined \%1 ask \%1 {File name? }
set input echo off
set input buffer-length 200000
# Tell it what size to plot
echo Triggering plot output...
output plot 0,0,60000,40000;
log session "\%1.hgl"
# Wait for end of data stream
input 400 SP;
echo ... HPGL data captured
close session
close
echo Converting HPGL in
echo --\%1.hgl
echo to PNG in
echo --\%1.png
run hp2xx -m png -c 143 "\%1.hgl"
echo Cropping and resizing
run mogrify -crop "515x395+0+0!" "\%1.png"
run mogrify -density 300 -resize 200% "\%1.png"
echo Finished!
exit 0
Here’s a picture of the FM broadcast band, as seen from the Basement Laboratory. The marker looks a bit off from 104.7 MHz, but that’s a combination of broad span and skinny peaks.
Back in the early 90s I bought a Hewlett Packard 54602B digital oscilloscope: 150 MHz bandwidth, 4 channels. By and large, a fine piece of gear that’s been worth every penny.
Over the objections of the HP sales force, I got the HP 54651A RS-232 interface rather than the HP 54650A HPIB (aka GPIB, aka IEEE-488) interface. Reasoning: I’d need a matching interface on the PC side and PC architecture is anything but stable. Turns out that was a good decision, as you’ll realize if you count up the number of different buses since those days and factor in the cost of an IEEE-488 interface for each iteration. RS-232 is slow and not well-suited for complex arrays of test gear, but mostly I needed the scope for screen shots to go with my Circuit Cellar columns.
Here’s how that works…
Configure the scope by poking the RS-232 softkey in Print/Utility:
Connect to: HP Plot
Factors: On (this is absolutely vital)
Resolution: High
Baud Rate: 19200 (yes, “baud rate” is an oxymoron)
Handshake: DTR
Now the scope will dump HPGL to what it thinks is a plotter, so the trick is to make the PC look like a plotter. Turns out that’s not particularly difficult.
Despite the name, DTR handshaking does not use the scope’s DTR pin. The relevant manual section looks like this (click the thumbnail for full-size image):
HP54602B Oscilloscope Serial Port Pin Functions
So DTR remains high and the flow-control signaling actually uses the RTS/CTS pins. The cable I’ve been is basically a null modem connection with the appropriate gender on each end:
PC RS-232
HP 54602B Oscilloscope
9-pin F
Signal
25-pin M
Signal
1
DCD
20
DTR
2
RxD
2
TxD
3
TxD
3
RxD
4
DTR
6
DSR
also->
8
DCD
5
Gnd
7
GND
6
DSR
20
DTR
7
RTS
5
CTS
8
CTS
4
RTS
9
RI
n/c
Note:
PC 1 and 6 <- scope 20
PC 4 -> scope 6 and 8
I wired the cable like that mostly because I have a lifetime supply of nice 9-conductor shielded cable lying around. You could connect the scope’s DTR to its own DSR and DCD pins, apply similar trickery on the PC end, and everybody would be perfectly happy with 5-conductor cable, maybe even 4-conductor if you ran the ground through the shield.
Using XON/XOFF flow control seems to not work well, although I admit to not trying too hard to figure it out.
These days, I use a USB-to-RS-232 converter with the now-standard 9-pin connector. The port identifier may be nearly anything after udev/hotplug has its way with the hardware, but it usually works out to /dev/ttyUSB0.
The script requires C-Kermit (likely the ckermit package), ImageMagick, sed, and hp2xx (yes, spelled exactly like that), all of which should be packages in your favorite Linux distro. Haven’t a clue how this might work with Windows.
With all that in hand, copy-n-paste the following text into a file (I used gethp54602, for lack of anything more original), make it executable (chmod u+x gethp54602) and run it with a file name (./gethp54602 test). Poke the Print Screen softkey on the scope and settle back for a bit. The scope can’t keep up a steady flow of data at 19200 b/s, so the whole affair takes a minute or three for the 50-ish kB of text in a dual-trace image.
You’ll end up with three files:
test.hgl — raw HPGL text from the ‘scope
test.eps — raster conversion from HPGL
test.png — bitmapped screen-capture image
The magic script…
#!/usr/bin/kermit +
# Fetches screen shot from HP54602B oscilloscope
# Presumes it's set up for plotter output...
# Converts HPGL to PNG image
set modem none
set line /dev/ttyUSB0
set speed 19200
set flow rts/cts
set carrier-watch off
# Make sure we have a param
if not defined \%1 ask \%1 {File name? }
set input echo off
set input buffer-length 200000
# Wait for PRINT button to send the plot
echo Set HP54602B for HP Plotter, FACTORS OFF, 19200, DTR
echo Press PRINT SCREEN button on HP54602B...
log session "\%1.hgl"
# Wait for final character
input 480 \x03
close session
close
echo Converting HPGL in
echo --\%1.hgl
echo to PNG in
echo --\%1.png
# Without factors
#run hp2xx -m png -a 1.762 -h 91 -c 14 "\%1.hgl"
#run mogrify -density 300 -resize 200% "\%1.png"
# With factors
run sed '/lb/!d' "\%1.hgl" > "\%1-1.hgl"
run hp2xx -q -m eps -r 270 -a 0.447 -d 300 -w 130 -c 14 -p 34 -f "\%1.eps" "\%1-1.hgl"
run rm "\%1-1.hgl"
run convert -density 300 -resize 675x452+2+2 "\%1.eps" "\%1.png"
echo Finished!
exit 0
[Update: WordPress unpredictably and ruthlessly mangles source code by incorrectly escaping some symbols. The line with sed should have a greater-than symbol to pipe the result into the .hgl file. A more recent version (albeit using my SENA PS410 serial server) hosted as a GitHub gist may help.]
Here’s a sample of what pops out; it’s the scope’s own calibrator waveform, nothing exciting, but you get the general idea.
Screen Capture of Calibrator Signal
The commented-out section labeled “Without Factors” converts the format you get with Factors Off. Turns out that there’s no unique ending string without factors, which puts a real crimp in getting the data. The advantage is that the HPGL converts directly to PNG and looks good. The only way I’ve found to capture the scope data is to just time out after a while.
With Factors On, however, the image data has a unique ending character (ASCII ETX, 0x03) after the label text, but the layout is rotated to plot in landscape mode. A direct conversion to PNG looks awful, perhaps because hp2xx must do software character generation, and I eventually figured out that making a bank shot off EPS vector format produced much better results.
However, hp2xx dutifully renders the text into the EPS image, but it doesn’t inject a carriage return after each linefeed: the text dribbles off to the far right of the actual screen image. To fix that, the sed editor hacks off the label text following the lb command. Mercifully, hp2xx doesn’t choke on the incomplete command.
And then convert does its usual magic. The image size is just right to drop into my Circuit Cellar columns; you may want something different for your purposes.
[Update: The PNG has an alpha channel that selects only the traces, so the background color depends on where you put it. A small tweak is there.]
For reasons that I absolutely do not understand, I cannot control the oscilloscope through the serial interface. The scope sends data to the PC just fine and I can get the scope to complain about the character format if I send truly bogus junk (like, mismatching the baud settings), but it simply will not respond to commands. Maybe the interface is broken or, more likely, I’m screwing something up. Hasn’t been a problem, though, for my simple needs.
Memo to Self: One of these days, eBay will have a 54652B serial/parallel interface that might work better.
I needed the conversions for a WWVB simulator, so it knows when to twiddle the leap-year and leap-second bits.
The general notion is a table with the Day-of-Year values for the last day of each month. The most expedient way of doing this is with two columns: one for normal years and the other for leap years, thusly…
Month
EOM
EOM-LY
DOY
DOY-LY
0
0
0
0
0
1
31
31
31
31
2
28
29
59
60
3
31
31
90
91
4
30
30
120
121
5
31
31
151
152
6
30
30
181
182
7
31
31
212
213
8
31
31
243
244
9
30
30
273
274
10
31
31
304
305
11
30
30
334
335
12
31
31
365
366
Hint: even if you can recite the “Thirty days hath November …” jingle, it’s much better to build a spreadsheet so the additions all work out. It’s even better if you don’t attempt any of this with a late-summer head cold. You might want to check all my work, because I’m still stuffy.
With table in hand, the code is straightforward.
Define a structure with all the various bits & pieces of the current time, much of which isn’t used here. It’s all needed in the WWVB simulator:
enum EVENTSTATE {EVENT_INACTIVE,EVENT_PENDING,EVENT_ACTIVE};
struct timecode_ { // The current moment in time...
byte Year; // 0 - 99
word DayOfYear; // 1 - 366
byte Hour; // 0 - 23
byte Minute; // 0 - 59
byte Second; // 0 - 60 (yes!)
byte Tenth; // 0 - 9
enum EVENTSTATE LeapYear; // 0 = no, 1 = pending, 2 = active
enum EVENTSTATE LeapSecond; // 0 = no, 1 = pending, 2 = active in this minute
enum EVENTSTATE DaylightSavingTime; // 0 = no, 1 = pending, 2 = active
char UT1Correction; // 100 ms units, -10 to +10 range (+/- 1 second)
byte MinuteLength; // 60 or 61
byte Month; // 1 - 12 (not sent in frame)
byte DayOfMonth; // 1 - 28..31 (not sent in frame)
};
That’s obviously overspecified, because DayOfYear with LeapYear uniquely determines Month and DayOfMonth. It’s handy to have both forms around, sooo there they are.
Then set up the table, glossing over the quick matrix transposition that turns the entries for each year into rows rather than columns:
Conversion from DayOfYear to Month and DayOfMonth requires searching backwards through the appropriate table row until you find the entry that’s smaller than the DayOfYear value, at which point you’ve found the right month.
void ConvertDOYtoDOM(struct timecode_ *pTime) {
byte Index,LY;
word EndOfMonth;
LY = (EVENT_INACTIVE != pTime->LeapYear) ? 1 : 0;
Index = 12;
while ((EndOfMonth = pgm_read_word(&MonthEnds[LY][Index])) >= pTime->DayOfYear) {
--Index;
};
pTime->Month = Index + 1; // months start with 1, not 0
pTime->DayOfMonth = (byte)(pTime->DayOfYear - EndOfMonth);
}
Converting from Month and DayOfMonth to DayOfYear is much easier, as it’s pretty much just a table lookup:
This code might actually work, but if I were you, I’d test it pretty thoroughly before lashing it into your project…
The PROGMEM and pgm_read_word() stuff is the Arduino mechanism that puts the lookup table into Flash program memory rather than the ATMega168’s exceedingly limited RAM space. The definitive word about that process resides there.
Memo to Self: Using const simply makes the variable kinda-sorta read-only, but still initializes RAM from Flash. The PROGMEM routines delete the RAM copy entirely.
Although the Arduino language looks like C and parses like C and runs like C, it’s not really C. It’s a specialized language gnawed on by a vast conversion monster and eventually shat out as executable ATmega-style instructions.
Here’s a (rather contrived) trivial working program…
#define PIN_ARDUINOLED 13 // standard LED
typedef struct {
int initial;
int on;
int off;
int reps;
} timeout_ ;
timeout_ Trial = {2000,100,1000,5};
void setup() {
pinMode(PIN_ARDUINOLED,OUTPUT);
}
void loop() {
int counter;
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.initial);
for (counter = 0; counter < Trial.reps; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(Trial.on);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.off);
}
}
That compiles and runs just like you’d expect: a long delay, followed by five blinks, repeating endlessly.
Now, use some preprocessor conditionals to gut-and-replace the code, with a bit of garish colorization to make things more obvious. This is Bad Programming Practice, but work with me…
#define PIN_ARDUINOLED 13 // standard LED
#if 0
typedef struct {
int initial;
int on;
int off;
int reps;
} timeout_ ;
#endif
#if 0
timeout_ Trial = {2000,100,1000,5};
#else
int LoopCount = 50;
#endif
void setup() {
pinMode(PIN_ARDUINOLED,OUTPUT);
}
void loop() {
int counter;
#if 0
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.initial);
for (counter = 0; counter < Trial.reps; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(Trial.on);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.off);
}
#else
digitalWrite(PIN_ARDUINOLED,LOW);
for (counter = 0; counter < LoopCount; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(250);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(500);
}
#endif
}
The error message lump resulting from compiling that looks like:
In function ‘void setup()’:
error: ‘OUTPUT’ was not declared in this scope In function ‘void loop()’:
In function ‘int main()’:
Really?
Delete the lines already removed by the preprocessor, the lines that shouldn’t be there when the code reaches the compiler, and you have:
#define PIN_ARDUINOLED 13 // standard LED
int LoopCount = 50;
void setup() {
pinMode(PIN_ARDUINOLED,OUTPUT);
}
void loop() {
int counter;
digitalWrite(PIN_ARDUINOLED,LOW);
for (counter = 0; counter < LoopCount; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(250);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(500);
}
}
Which compiles and runs like a champ, of course. It blinks merrily away, more off than on, forever. The LoopCount variable doesn’t do much for us, but it’s the thought that counts.
Put the original lines back, comment out the new stuff, and you get:
#define PIN_ARDUINOLED 13 // standard LED
typedef struct {
int initial;
int on;
int off;
int reps;
} timeout_ ;
timeout_ Trial = {2000,100,1000,5};
#if 0
int LoopCount = 50;
#endif
void setup() {
pinMode(PIN_ARDUINOLED,OUTPUT);
}
void loop() {
int counter;
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.initial);
for (counter = 0; counter < Trial.reps; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(Trial.on);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(Trial.off);
}
#if 0
digitalWrite(PIN_ARDUINOLED,LOW);
for (counter = 0; counter < LoopCount; ++counter) {
digitalWrite(PIN_ARDUINOLED,HIGH);
delay(250);
digitalWrite(PIN_ARDUINOLED,LOW);
delay(500);
}
#endif
}
And that compiles and runs perfectly, just like you’d expect. Uh-huh. Right.
Basically, there’s a complex interaction between ordinary C preprocessor directives, ordinary C language elements, and the inscrutable innards of the Arduino IDE & compiler chain.
As nearly as I can tell, you can wrap #if whatever around simple declarations and most executable code with impunity, but putting anything more elaborate than that, like a simple typedef struct, inside the conditionals causes bizarre problems.
In fact, just typedef can cause problems, particularly if you attempt to use the ensuing tag in a function declaration. Don’t even think about anything along these lines:
Trying to make sense of this will drive you mad (well, it drives me mad), but when you get bizarre error messages that can’t be explained by the usual operator screwups, well, most likely you’re being too clever with the preprocessor.
Or you’ve (also) made a trivial typo that cannot be discovered by inspection.
It seems the right (only?) way to handle typedef definitions is to put ’em in a separate header file, as described there, then add the header file to your sketch in a separate tab. That seems to insert the definitions in the proper order within the *.cpp file that actually goes into the compiler.
However, some limited fiddling reveals that I don’t understand the nuances or I’m screwing it up. Probably both.
Memo to Self: define the structs & variables without typedefs, then prepare for some protracted tweakage…
I have a stash of RTC65271 real-time clock modules and might use one in an upcoming project. They’re obsolete by nigh onto two decades, but it’s a one-off project and I know I’ve been saving these things for some good reason.
Alas, the datasheet doesn’t seem to appear anywhere else on the web; you can find an overview & general description, but not how the thing actually works.
However, if you happen to have a chip and need the datasheet, this is indeed your lucky day: a scanned RTC65271 Datasheet.
The datasheet alleges it’s “functionally compatible with MC146818A and DS1287“, and those datasheets may be more readable, if not exactly applicable. It seems to be (similar to) the clock chip used in the original PC/AT, if you recall those relics, and might actually use standard hardware & software protocols.
Dealing with this thing may be more trouble than it’s worth in this day of bus-less microcontrollers with Serial Peripheral Interface widgetry. A back-of-the-envelope count says it’d require three ‘595 output chips and a ‘166 input chip to fit on an SPI bus. Yuch…
Hey, if you want one, drop me a note. I have far more than a lifetime supply at my current rate of consumption.
Yes, yes, I know OpenOffice and its ilk have all the features you think you need. When you actually try to put together a book-length document, you find that the features don’t actually work / work together / behave reliably. Been there, done that. Enough times to be wary, indeed.
So LyX / LaTeX is the least-worst alternative and actually does a pretty good job after you get the various configurations beaten into shape. After that, you just type, add tags, and it’s all good.
Here’s a list of the settings I’m using… for future reference, natch, because figuring this stuff out from first principles takes a while.
Document settings
Document Class: report
Text Layout: MedSkip vertical, Single line, Two-column
Page Layout: US Letter, fancy headings
Page Margins: 0.75 inch all around, 0.3 inch separations</pre>
<strong>LaTeX Preamble</strong>
<pre>\usepackage{ragged2e}
\usepackage{lastpage}
\usepackage{url}
\usepackage{dvipost}
\usepackage{breakurl}
\usepackage[labelfont={bf,sf}]{caption}
\renewcommand{\bottomfraction}{0.7}
\pagestyle{fancyplain}
\fancyhf{}
\lhead{\fancyplain{}{Trinity College Home Robot Contests}}
\rhead{\fancyplain{}{2010 Rules}}
\lfoot{\fancyplain{Modified \today}{Modified \today}}
\cfoot{Copyright 2009 by Trinity College}
\rfoot{\fancyplain{\thepage\ of \pageref{LastPage}}{\thepage\ of \pageref{LastPage}}}
\RaggedRight
\dvipostlayout
\dvipost{cbstart color push Blue}
\dvipost{cbend color pop}
Trickery
Some of those packages aren’t part of the default LyX / LaTeX installation on Ubuntu. Searching for LaTeX in Synaptic is tedious, but works.
The three ways to export to PDF are not identical.
dvipdfm doesn’t produce clickable TOC links.
pdflatex, the default, doesn’t produce change bars, which is a crippling defect for a rules document under heavy revision. It’s OK for the final draft, though.
ps2pdf doesn’t produce searchable text; it’s all graphics. Ptooie!
So use dvipdfm during development (to get change bars) and use pdflatex for the final product (to get clickable links). There has got to be a way around that, but I haven’t a clue as to what’s going on under the hood.
In order to track changes:
Document -> Change Tracking -> Track Changes.
In order to print change bars and suchlike:
Document -> Change Tracking -> Show Changes in Output
Figures appear on-screen in dot-for-dot mode by default, so tweak the on-screen ratio to maybe 50%. Force the printed width of all figures to 3 inches for two-column layout. Insist that picture resolution bear some resemblance to reality: 3 inches at 300 dpi -> 1000 pixels across.
There seems to be no way to export LyX directly to ODT. Exporting to RTF strips off most of the formatting, as you’d expect, and change tracking Goes Away.
Exporting to HTML produces one honkin’ big lump of HTML with a bazillion image files in a separate directory. That’s probably OK for most purposes.
Memo to Self: Turn off change tracking for minor editorial tweakage, because nobody really cares.
The model has some limitations, discussed there, but seems practical. So far, the main gotcha is that the output voltage doesn’t center neatly at Vcc/2, but that’s in the nature of fine tuning.
The trick is getting the model & symbol into Linear Technology’s LTSpiceIV…
Running under WINE in Xubuntu, the emulated C drive is in your home directory at
.wine/drive_c/
with the Linear Tech LTSpiceIV files tucked inside that at
.wine/drive_c/Program\ Files/LTC/LTspiceIV/
Incidentally, WINE puts the program icon in
.local/share/icons/05f1_scad3.0.xpm
It’s not clear what the prefix means, but the actual executable is scad3.exe (I think that’s historical cruft, as the new overall name is LTSpiceIV).
Copy the LM386.sub file to lib/sub and the LM386.asy file to lib/sym, then restart LTSpiceIV.
After putting the symbol in the schematic, I had to edit its attributes (other-click the symbol), make both InstName & Value visible to see them on the schematic, then move them to somewhere other than dead-center in the symbol. I can’t figure out how to make that happen automagically, as it does with other symbols. Comparing the two files to ordinary components doesn’t show anything obviously missing.
Link rot being what it is, here’s the LM386.sub file:
* lm386 subcircuit model follows:
************************************original* IC pins: 2 3 7 1 8 5 6 4
* IC pins: 1 2 3 4 5 6 7 8
* | | | | | | | |
.subckt lm386 g1 inn inp gnd out vs byp g8
************************************original*.subckt lm386 inn inp byp g1 g8 out vs gnd
* input emitter-follower buffers:
q1 gnd inn 10011 ddpnp
r1 inn gnd 50k
q2 gnd inp 10012 ddpnp
r2 inp gnd 50k
* differential input stage, gain-setting
* resistors, and internal feedback resistor:
q3 10013 10011 10008 ddpnp
q4 10014 10012 g1 ddpnp
r3 vs byp 15k
r4 byp 10008 15k
r5 10008 g8 150
r6 g8 g1 1.35k
r7 g1 out 15k
* input stage current mirror:
q5 10013 10013 gnd ddnpn
q6 10014 10013 gnd ddnpn
* voltage gain stage & rolloff cap:
q7 10017 10014 gnd ddnpn
c1 10014 10017 15pf
* current mirror source for gain stage:
i1 10002 vs dc 5m
q8 10004 10002 vs ddpnp
q9 10002 10002 vs ddpnp
* Sziklai-connected push-pull output stage:
q10 10018 10017 out ddpnp
q11 10004 10004 10009 ddnpn 100
q12 10009 10009 10017 ddnpn 100
q13 vs 10004 out ddnpn 100
q14 out 10018 gnd ddnpn 100
* generic transistor models generated
* with MicroSim's PARTs utility, using
* default parameters except Bf:
.model ddnpn NPN(Is=10f Xti=3 Eg=1.11 Vaf=100
+ Bf=400 Ise=0 Ne=1.5 Ikf=0 Nk=.5 Xtb=1.5 Var=100
+ Br=1 Isc=0 Nc=2 Ikr=0 Rc=0 Cjc=2p Mjc=.3333
+ Vjc=.75 Fc=.5 Cje=5p Mje=.3333 Vje=.75 Tr=10n
+ Tf=1n Itf=1 Xtf=0 Vtf=10)
.model ddpnp PNP(Is=10f Xti=3 Eg=1.11 Vaf=100
+ Bf=200 Ise=0 Ne=1.5 Ikf=0 Nk=.5 Xtb=1.5 Var=100
+ Br=1 Isc=0 Nc=2 Ikr=0 Rc=0 Cjc=2p Mjc=.3333
+ Vjc=.75 Fc=.5 Cje=5p Mje=.3333 Vje=.75 Tr=10n
+ Tf=1n Itf=1 Xtf=0 Vtf=10)
.ends
*----------end of subcircuit model-----------
And the corresponding LM386.asy file:
Version 4
SymbolType CELL
LINE Normal -64 -63 64 0
LINE Normal -64 65 64 0
LINE Normal -64 -63 -64 65
LINE Normal -60 -48 -52 -48
LINE Normal -60 48 -52 48
LINE Normal -56 52 -56 44
LINE Normal -48 -80 -48 -55
LINE Normal -48 80 -48 57
LINE Normal -44 -68 -36 -68
LINE Normal -40 -72 -40 -64
LINE Normal -44 68 -36 68
LINE Normal -16 -39 -16 -64
LINE Normal 0 32 0 48
LINE Normal 48 -8 48 -32
SYMATTR Value LM386
SYMATTR Prefix X
SYMATTR ModelFile LM386.sub
SYMATTR Value2 LM386
SYMATTR Description Low power audio amplifier
PIN -16 -64 LEFT 8
PINATTR PinName g1
PINATTR SpiceOrder 1
PIN -64 -48 NONE 0
PINATTR PinName In-
PINATTR SpiceOrder 2
PIN -64 48 NONE 0
PINATTR PinName In+
PINATTR SpiceOrder 3
PIN -48 80 NONE 0
PINATTR PinName V-
PINATTR SpiceOrder 4
PIN 64 0 NONE 0
PINATTR PinName OUT
PINATTR SpiceOrder 5
PIN -48 -80 NONE 0
PINATTR PinName V+
PINATTR SpiceOrder 6
PIN 0 48 LEFT 8
PINATTR PinName bp
PINATTR SpiceOrder 7
PIN 48 -32 LEFT 8
PINATTR PinName g8
PINATTR SpiceOrder 8