When buying electronic parts it sometimes is cheaper to buy in the USA. There are some caveats concerning shipping though.
UPS
While sometimes a bit cheaper (but I usually end up with free shipping because I cluster my buys), there is one very big drawback, and that is import tax.
With UPS you have to pay the import tax in cash to the driver. Because you don't know the exact amount at order time you have to guess how much money you need to have in house and then some more because the driver usually can't give change back.
DHL & FEDEX
With DHL & FEDEX you don't pay the import tax to the driver, you get a separate bill via snail mail, which you can pay via a normal wire transfer. Much better!
Consequences
That being said, this starts to influence my buying choices. For example digikey usually ships with UPS, while mouser allows me to choose FEDEX, which makes mouser my preferred choice for buying parts from the USA.
When buying in Europe it doesn't matter so for farnell and rsonline I don't mind either. If I can buy at either of those I still prefer that but both digikey and mouser have a somewhat larger and different selection.
Others
I basically buy most parts at those 4, and sometimes sparkfun or one of sparkfun's resellers of course. Are there any other shops you recommend ?
Monday, April 30, 2012
Thursday, April 26, 2012
3D printing a LED diffuser directly on PCB
"3D printing a LED diffuser directly on PCB"
Yes, it is possible. Hence this quick blog post.
This lamp is a simple proto PCB with a whole lot (>30) of high brightness 0603 white LEDs soldered on them with a few layers of 3D printed yellow PLA on top of them.
I had to add some DRAM heat-sinks to the back to deal with the massive heat production, especially given that PLA gets liquid at relatively low temperatures. Light production is quite poor, but it is cool for mood lighting.
To be continued.
Yes, it is possible. Hence this quick blog post.
This lamp is a simple proto PCB with a whole lot (>30) of high brightness 0603 white LEDs soldered on them with a few layers of 3D printed yellow PLA on top of them.
I had to add some DRAM heat-sinks to the back to deal with the massive heat production, especially given that PLA gets liquid at relatively low temperatures. Light production is quite poor, but it is cool for mood lighting.
To be continued.
Sunday, April 1, 2012
3D printing and openSCAD
Yesterday, March 2012, I gave a short talk about 3D printing and openSCAD at Newline^2, the conference at 0x20.
The slides and embedded pictures are available under the Creative Commons Attribution-ShareAlike 3.0.
Click here to get them as PDF.
The slides and embedded pictures are available under the Creative Commons Attribution-ShareAlike 3.0.
Click here to get them as PDF.
Labels:
lang:en,
programming
Saturday, March 10, 2012
Arduino, limited RAM and PROGMEM
And so I was happily adding more and more descent error handling code to a piece of code running on an atmega328p (the Atmel AVR micro-controller also typically used in Arduino). And then the thing started acting up. Now I've had that happen to me before so I immediately thought that it was running out of RAM.
The atmega328p has 32k flash, which is typically plenty, but it has only 2k RAM, which is not very much at all.
I was doing things like:
Serial.println("FAIL invalid argument");
Now, you might be thinking, why does it have to store the "FAIL invalid argument" in RAM?
It has all to do with how braindead C/C++ is/are.
"FAIL invalid argument" is a "const char *" which although it seems read-only it actually isn't (and no "const char const *" isn't either).
Thing is in C it is perfectly legal to cast away any types and just start changing characters in the string.
And the compiler can't know you're not doing that as you could be doing it via some very scary indirect pointer arithmetic to get to the characters in the string.
Bottom line is that every "constant" string in the code is copied to RAM because it could theoretically be used.
Now, on to PROGMEM.
It is a way to use strings directly as contained in the program code, but without the copying to RAM.
Okay, I'll first give the short answer which works fine on arduino 0.22 or newer:
Serial.println(F("FAIL invalid argument"));
This does some casting and other magic in the back and does the right thing.
Just for educational purposes lets take a look how to do it without arduino tricks.
the <avr/pgmspace.h> header contains a useful macro, called PSTR which looks like we could use it just like this:
Serial.println(PSTR("FAIL invalid argument"));
Unfortunately that doesn't work. PSTR returns a PROGMEM pointer and it turns out (even though the atmega has a flat address space) we can't use PROGMEM pointers just like regular pointers.
It will nicely compile and give garbage.
The only way is copying the data from PROGMEM to RAM and then using it.
This could be done byte-by-byte with pgm_read_byte (this is what arduino does internally, take a peek in arduino-1.0/hardware/arduino/cores/arduino/Print.cpp ) or to a buffer in RAM with strcpy_P.
All this is quite awkward and error-prone and makes me long for a nicer language for microcontrollers ;)
The atmega328p has 32k flash, which is typically plenty, but it has only 2k RAM, which is not very much at all.
I was doing things like:
Serial.println("FAIL invalid argument");
Now, you might be thinking, why does it have to store the "FAIL invalid argument" in RAM?
It has all to do with how braindead C/C++ is/are.
"FAIL invalid argument" is a "const char *" which although it seems read-only it actually isn't (and no "const char const *" isn't either).
Thing is in C it is perfectly legal to cast away any types and just start changing characters in the string.
And the compiler can't know you're not doing that as you could be doing it via some very scary indirect pointer arithmetic to get to the characters in the string.
Bottom line is that every "constant" string in the code is copied to RAM because it could theoretically be used.
Now, on to PROGMEM.
It is a way to use strings directly as contained in the program code, but without the copying to RAM.
Okay, I'll first give the short answer which works fine on arduino 0.22 or newer:
Serial.println(F("FAIL invalid argument"));
This does some casting and other magic in the back and does the right thing.
Just for educational purposes lets take a look how to do it without arduino tricks.
the <avr/pgmspace.h> header contains a useful macro, called PSTR which looks like we could use it just like this:
Serial.println(PSTR("FAIL invalid argument"));
Unfortunately that doesn't work. PSTR returns a PROGMEM pointer and it turns out (even though the atmega has a flat address space) we can't use PROGMEM pointers just like regular pointers.
It will nicely compile and give garbage.
The only way is copying the data from PROGMEM to RAM and then using it.
This could be done byte-by-byte with pgm_read_byte (this is what arduino does internally, take a peek in arduino-1.0/hardware/arduino/cores/arduino/Print.cpp ) or to a buffer in RAM with strcpy_P.
All this is quite awkward and error-prone and makes me long for a nicer language for microcontrollers ;)
Friday, January 20, 2012
arduino mega and multiple hardware serial devices
For a project I use an arduino mega (Atmel AtMega1280 8-bit micro-controller to be precise) to access multiple other hardware devices via hardware serial.
I'm running the Arduino stack on the hardware, more specific the arduino 1.0 release.
Now the atmega1280 (or atmega2560) has 4 hardware serial devices (called Serial, Serial1, Serial2, Serial3 in arduino) so using multiple serial devices is easy eh?
Not really.
For one use case I have a device connected on Serial1 at 57600 baud.
I want to be able to route serial traffic from that device to the Serial device connected to the PC.
Sounds easy enough, the follow arduino sketch does the job:
Thing is, for short messages this works fine. However for longer messages only one direction is stable, the direction from the external device (Serial1) to the serial port (Serial).
I could run the serial port (Serial) at a slower speed then the device (Serial1). However then the other way around will start to drop bytes!
Let's have a look at HardwareSerial.cpp as provided in the arduino distribution.
It seems to work with an RX and TX buffer for each hardware serial device.
Maybe that buffer is not large enough. The AtMega1280 I'm using has 8K SRAM and thats quite some more then I need. Let's double the buffer.
Surely the behavior is somewhat better, but it is still dropping bytes in one direction.
Let's have a look at the write function.
Look and behold:
it's a busy loop! If Serial1's transfer buffer is full the entire micro-controller will block and this keeps happening all the time.
The solution I introduced is only move data from one serial device to the other when both are ready. One should be readable (available() in arduino jargon) and the other should be writeable.
A writeable function is not available in Arduino so I added the following method to the HardwareSerial code:
The loop from the sketch now looks like this:
This helps in the sense that it smooths the flow between the serial devices.
No more dropped bytes!
I'm running the Arduino stack on the hardware, more specific the arduino 1.0 release.
Now the atmega1280 (or atmega2560) has 4 hardware serial devices (called Serial, Serial1, Serial2, Serial3 in arduino) so using multiple serial devices is easy eh?
Not really.
For one use case I have a device connected on Serial1 at 57600 baud.
I want to be able to route serial traffic from that device to the Serial device connected to the PC.
Sounds easy enough, the follow arduino sketch does the job:
void setup(){
Serial.begin(57600);
Serial1.begin(57600);}
void loop() {
// from external device to serial console
if (Serial1.available() > 0) {
byte incomingByte = Serial1.read();
Serial.write(incomingByte);
}
// from serial console to external device
if (Serial.available() > 0) {
byte incomingByte = Serial.read();
Serial1.write(incomingByte);
}
}
Thing is, for short messages this works fine. However for longer messages only one direction is stable, the direction from the external device (Serial1) to the serial port (Serial).
I could run the serial port (Serial) at a slower speed then the device (Serial1). However then the other way around will start to drop bytes!
Let's have a look at HardwareSerial.cpp as provided in the arduino distribution.
It seems to work with an RX and TX buffer for each hardware serial device.
#define SERIAL_BUFFER_SIZE 64
Maybe that buffer is not large enough. The AtMega1280 I'm using has 8K SRAM and thats quite some more then I need. Let's double the buffer.
#define SERIAL_BUFFER_SIZE 128
Surely the behavior is somewhat better, but it is still dropping bytes in one direction.
Let's have a look at the write function.
size_t HardwareSerial::write(uint8_t c){
int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
// ???: return 0 here instead?
while (i == _tx_buffer->tail)
;
_tx_buffer->buffer[_tx_buffer->head] = c;
_tx_buffer->head = i;
sbi(*_ucsrb, _udrie);
return 1;}
Look and behold:
while (i == _tx_buffer->tail) ;
it's a busy loop! If Serial1's transfer buffer is full the entire micro-controller will block and this keeps happening all the time.
The solution I introduced is only move data from one serial device to the other when both are ready. One should be readable (available() in arduino jargon) and the other should be writeable.
A writeable function is not available in Arduino so I added the following method to the HardwareSerial code:
bool HardwareSerial::writeable(){
int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;
return (i != _tx_buffer->tail);}
The loop from the sketch now looks like this:
void loop() {
if (Serial1.available() > 0 && Serial.writeable()) {
byte incomingByte = Serial1.read();
Serial.write(incomingByte);
}
if (Serial.available() > 0 && Serial1.writeable()) {
byte incomingByte = Serial.read();
Serial1.write(incomingByte);
}
}
This helps in the sense that it smooths the flow between the serial devices.
No more dropped bytes!
Labels:
arduino,
atmega,
avr,
lang:en,
programming
Monday, July 18, 2011
X with xmonad without KDE/gnome, continued
This is the setup I settled upon in the end, it's working great. It has heavily based on this wiki page.
The .xsession file:
In order to have X execute the .xsession isof starting the window manager itself, choose the "System default" as session type in gdm or kdm.
This is my .Xresource file:
This is the .xmobarrc file:
ancalagon is the name of my laptop.
Finally, this is the .xmonad/xmonad.hs file:
With big thanks to John Goerzen for providing the excellent information.
The .xsession file:
#!/bin/bash
# Load resources
xrdb -merge .Xresources
# Set up an icon tray
trayer --edge top --align right --SetDockType true --SetPartialStrut true \
--expand true --width 10 --transparent true --tint 0x191970 --height 12 &
# Set the background color
xsetroot -solid midnightblue
# Fire up apps
xscreensaver -no-splash &
if [ -x /usr/bin/nm-applet ] ; then nm-applet --sm-disable & fi
if [ -x /usr/bin/gnome-power-manager ] ; then sleep 3 gnome-power-manager & fi
#xset b off
eval `gpg-agent --daemon`
eval `ssh-agent --daemon`
setxkbmap -option compose:caps
exec xmonad
In order to have X execute the .xsession isof starting the window manager itself, choose the "System default" as session type in gdm or kdm.
This is my .Xresource file:
# red cursor Color, looks great in combination with xmonad
xterm*cursorColor: red
# save tons of lines
xterm*saveLines: 100000
# triple click like in konsole/gnome-termimal
xterm*on3Clicks: regex [^ \n]+
xterm*on4Clicks: line
# use fancy terminus font
xterm*FaceName: terminus-10
This is the .xmobarrc file:
Config { font = "-*-Fixed-Bold-R-Normal-*-13-*-*-*-*-*-*-*"
, bgColor = "black"
, fgColor = "grey"
, position = TopW L 90
, lowerOnStart = True
, commands = [
Run Weather "EBDT" ["-t"," C","-L","64","-H","77","--normal","green","--high","red","--low","lightblue"] 36000,
Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10,
Run Memory ["-t","Mem: %"] 10,
Run Swap [] 10,
Run Date "%a %b %_d %H:%M" "date" 10,
Run StdinReader
]
, sepChar = "%"
, alignSep = "}{"
, template = "%StdinReader% }{ ancalagon %cpu% | %memory% * %swap% %date% | %EBDT%"
}
ancalagon is the name of my laptop.
Finally, this is the .xmonad/xmonad.hs file:
import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import System.IO
main = do
xmproc <- spawnPipe "xmobar"
xmonad $ defaultConfig
{ manageHook = manageDocks <+> manageHook defaultConfig
, layoutHook = avoidStruts $ layoutHook defaultConfig
, logHook = dynamicLogWithPP xmobarPP
{ ppOutput = hPutStrLn xmproc
, ppTitle = xmobarColor "green" "" . shorten 50
}
--, modMask = mod4Mask -- Rebind Mod to the Windows key
} `additionalKeys`
[ ((controlMask .|. shiftMask, xK_z), spawn "xscreensaver-command -lock")
, ((controlMask, xK_Print), spawn "sleep 0.2; scrot -s")
, ((0, xK_Print), spawn "scrot")
]
With big thanks to John Goerzen for providing the excellent information.
Sunday, July 10, 2011
configuring X with xmonad without KDE/gnome
While configuring X11 to use the xmonad tiling window manager instead of the more usual KDE or GNOME, some things were somewhat less then obvious, and I document them here.
.xsession configuration
These are settings that all can be made permanent by adding them to the
.xsession file in your home directory.
disable CAPS, enable Compose
setxkbmap -option compose:caps
Now you can use the Caps Lock key to compose special characters. E.g.
disable beep globally
xset b off
start gpg-agent on startup
.xsession configuration
These are settings that all can be made permanent by adding them to the
.xsession file in your home directory.
disable CAPS, enable Compose
setxkbmap -option compose:caps
Now you can use the Caps Lock key to compose special characters. E.g.
- <Caps> 'e gives é
- <Caps> e= gives €
- ...
... and as a bonus you can't accidentally press the Caps Lock key any more!
disable beep globally
xset b off
start gpg-agent on startup
eval `gpg-agent --daemon`
start ssh-agent on startup
eval `ssh-agent --daemon`
other things
dmenu
Install the suckless-tools package for dmenu among things.
Just use <alt>-p to quicklanch apps with dmenu.
xterm
I want to use plain xterm as terminal emulator as the tabbing of gnome-terminal and konsole is rather pointless in combination with the tiling.
The default font size was to small. To solve this I did a dirty hack like this:
- update-alternatives -config xterm and change it to uxterm to have an UTF-8 terminal by default
- edit /usr/bin/uxterm and change the last line by adding -fn 10x20 to it.
email
At the moment I'm still using kmail as email client (and accidentally akregator as RSS feed agregator). I'm still thinking about switching that as well.
... to be continued ...
Subscribe to:
Posts (Atom)