tag:blogger.com,1999:blog-61858749529189816862024-03-16T02:10:14.407-07:00Coding LaboratoryA collection of small hacksRaulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-6185874952918981686.post-39076446397076434062016-04-18T15:29:00.003-07:002016-04-21T16:51:44.531-07:00Arduino-PID-Library online Trainer
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<style>
fieldset {
border: 0;
}
label {
display: block;
margin: 30px 0 0 0;
}
select {
width: 300px;
}
</style>
<script>
class PDI
{
/*Constructor (...)*********************************************************
* The parameters specified here are those for for which we can't set up
* reliable defaults, so we need to have the user set them.
***************************************************************************/
constructor(Input, Output, Setpoint, Kp, Ki, Kd, ControllerDirection)
{
this.myOutput = Output;
this.myInput = Input;
this.mySetpoint = Setpoint;
this.inAuto = false;
this.SetOutputLimits(0, 255); //default output limit corresponds to
//the arduino pwm limits
this.SampleTime = 100; //default Controller Sample Time is 0.1 seconds
this.SetControllerDirection(ControllerDirection);
this.SetTunings(Kp, Ki, Kd);
this.lastTime = 0-this.SampleTime;
}
SetSetPoint(Setpoint) {this.mySetpoint = Setpoint;}
GetOutput() {return this.myOutput;}
SetInput(Input) {this.myInput = Input;}
/* Compute() **********************************************************************
* This, as they say, is where the magic happens. this function should be called
* every time "void loop()" executes. the function will decide for itself whether a new
* pid Output needs to be computed. returns true when the output is computed,
* false when nothing has been done.
**********************************************************************************/
Compute(now)
{
if(!this.inAuto) return false;
//unsigned long now = millis();
var timeChange = (now - this.lastTime);
if(timeChange>=this.SampleTime)
{
/*Compute all the working error variables*/
var input = this.myInput;
var error = this.mySetpoint - input;
this.ITerm+= (this.ki * error);
if(this.ITerm > this.outMax) this.ITerm= this.outMax;
else if(this.ITerm < this.outMin) this.ITerm= this.outMin;
var dInput = (input - this.lastInput);
/*Compute PID Output*/
var output = this.kp * error + this.ITerm- this.kd * dInput;
if(output > this.outMax) output = this.outMax;
else if(output < this.outMin) output = this.outMin;
this.myOutput = output;
/*Remember some variables for next time*/
this.lastInput = input;
this.lastTime = now;
return true;
}
else return false;
}
/* SetTunings(...)*************************************************************
* This function allows the controller's dynamic performance to be adjusted.
* it's called automatically from the constructor, but tunings can also
* be adjusted on the fly during normal operation
******************************************************************************/
SetTunings(Kp, Ki, Kd)
{
if (Kp<0 || Ki<0 || Kd<0) return;
this.dispKp = Kp; this.dispKi = Ki; this.dispKd = Kd;
var SampleTimeInSec = (this.SampleTime)/1000;
this.kp = Kp;
this.ki = Ki * SampleTimeInSec;
this.kd = Kd / SampleTimeInSec;
if(this.controllerDirection == -1)
{
this.kp = (0 - this.kp);
this.ki = (0 - this.ki);
this.kd = (0 - this.kd);
}
}
/* SetSampleTime(...) *********************************************************
* sets the period, in Milliseconds, at which the calculation is performed
******************************************************************************/
SetSampleTime(NewSampleTime)
{
if (NewSampleTime > 0)
{
var ratio = NewSampleTime / this.SampleTime;
this.ki *= ratio;
this.kd /= ratio;
this.SampleTime = NewSampleTime;
}
}
/* SetOutputLimits(...)****************************************************
* This function will be used far more often than SetInputLimits. while
* the input to the controller will generally be in the 0-1023 range (which is
* the default already,) the output will be a little different. maybe they'll
* be doing a time window and will need 0-8000 or something. or maybe they'll
* want to clamp it from 0-125. who knows. at any rate, that can all be done
* here.
**************************************************************************/
SetOutputLimits(Min, Max)
{
if(Min >= Max) return;
this.outMin = Min;
this.outMax = Max;
if(this.inAuto)
{
if(this.myOutput > this.outMax) this.myOutput = this.outMax;
else if(this.myOutput < this.outMin) this.myOutput = this.outMin;
if(this.ITerm > this.outMax) this.ITerm= this.outMax;
else if(this.ITerm < this.outMin) this.ITerm= this.outMin;
}
}
/* SetMode(...)****************************************************************
* Allows the controller Mode to be set to manual (0) or Automatic (non-zero)
* when the transition from manual to auto occurs, the controller is
* automatically initialized
******************************************************************************/
SetMode(Mode)
{
var newAuto = (Mode != 0);
if(newAuto == !this.inAuto)
{ /*we just went from manual to auto*/
this.Initialize();
}
this.inAuto = newAuto;
}
/* Initialize()****************************************************************
* does all the things that need to happen to ensure a bumpless transfer
* from manual to automatic mode.
******************************************************************************/
Initialize()
{
this.ITerm = this.myOutput;
this.lastInput = this.myInput;
if(this.ITerm > this.outMax) this.ITerm = this.outMax;
else if(this.ITerm < this.outMin) this.ITerm = this.outMin;
}
/* SetControllerDirection(...)*************************************************
* The PID will either be connected to a DIRECT acting process (+Output leads
* to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to
* know which one, because otherwise we may increase the output when we should
* be decreasing. This is called from the constructor.
******************************************************************************/
SetControllerDirection(Direction)
{
if(this.inAuto && Direction !=this.controllerDirection)
{
this.kp = (0 - this.kp);
this.ki = (0 - this.ki);
this.kd = (0 - this.kd);
}
this.controllerDirection = Direction;
}
/* Status Funcions*************************************************************
* Just because you set the Kp=-1 doesn't mean it actually happened. these
* functions query the internal state of the PID. they're here for display
* purposes. this are the functions the PID Front-end uses for example
******************************************************************************/
GetKp(){ return this.dispKp; }
GetKi(){ return this.dispKi;}
GetKd(){ return this.dispKd;}
GetMode(){ return this.inAuto ? AUTOMATIC : MANUAL;}
GetDirection(){ return this.controllerDirection;}
}
class heater
{
constructor(delay)
{
this.position = 0;
this.velocity = 0;
this.acceleration = 0;
this.delay = new Array(delay+2)
for(var i=1;i<this.delay.length;i++)
this.delay[i] = 0
}
setPoint(p)
{
this.delay[this.delay.length-1] = p;
}
integrate(SampleTime, constantForce)
{
// x += .5*a*t^2 + v*t
// v += a * t
for(var i=1;i<this.delay.length;i++)
this.delay[i-1] = this.delay[i]
var totalAcceleration = this.delay[0] + constantForce
this.position += .5 * totalAcceleration * SampleTime* SampleTime + this.velocity * SampleTime;
this.velocity += totalAcceleration * SampleTime;
this.velocity *=.97
return this.position
}
}
function lerp(a,b,t)
{
return a*(1-t)+b*t
}
function frac(a,b,v)
{
return (v - a)/(b-a)
}
function scaleYToCanvas(c, minY, maxY, y)
{
return lerp(c.height,0, frac(minY,maxY,y))
}
class graph
{
constructor(canvas, minY,maxY)
{
this.canvas = canvas
this.ctx = canvas.getContext("2d");
this.maxY = maxY
this.minY = minY
}
clear() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); }
drawScale()
{
this.ctx.beginPath();
this.ctx.strokeStyle = '#000000';
for(var t=-10;t<100;t+=10)
{
var tt = Math.round(this.scaleYToCanvas(t))
this.ctx.font = "15px Arial";
this.ctx.fillText(t,0,tt-2);
this.ctx.moveTo(10, tt);
this.ctx.lineTo(this.canvas.width, tt);
}
this.ctx.stroke();
}
drawPath(path)
{
this.ctx.beginPath();
this.ctx.strokeStyle = '#00f000';
var lastY=this.scaleYToCanvas(0)
this.ctx.moveTo(0, lastY);
for(var t=0;t<path.length;t+=2)
{
this.ctx.lineTo(path[t], lastY );
lastY= Math.round(this.scaleYToCanvas(path[t+1]))
this.ctx.lineTo(path[t], lastY);
}
this.ctx.stroke();
}
getContext() { return this.ctx; }
scaleYToCanvas(y) { return scaleYToCanvas(this.canvas, this.minY, this.maxY, y) }
}
function Heater(level, kp, kd, ki)
{
constantForce=0;
delay = 0;
if (level==2)
constantForce=5;
if (level==3)
delay = 5;
var canvas = document.getElementById("myCanvas");
var g = new graph(canvas,0,40)
var ctx = g.getContext();
g.clear()
var outputCanvas = document.getElementById("myOutputCanvas");
var g2 = new graph(outputCanvas,-10,10)
var ctx2 = g2.getContext();
g2.clear()
var p = new PDI(0, 0, 0, kp,ki,kd,1)
p.SetOutputLimits(-10, 10);
p.SetMode(1)
var h = new heater(delay)
h.setPoint(0);
g.drawScale()
g2.drawScale()
var path = [0,20, 200, 30, 400,10, 800,10];
g.drawPath(path)
ctx.beginPath();
ctx.strokeStyle = '#ff0000';
ctx2.beginPath();
ctx2.strokeStyle = '#ff0000';
time = 0;
for(var i=0;i<canvas.width;i+=1)
{
position = h.integrate(.1, constantForce)
time +=.1;
for(var ii=0;ii<path.length;ii+=2)
if (time*10 >= path[ii])
p.SetSetPoint(path[ii+1]);
p.SetInput(position)
p.Compute(time * 1000)
h.setPoint(p.GetOutput());
y = g.scaleYToCanvas(position)
y2 = g2.scaleYToCanvas(p.GetOutput())
if (i==0)
{
ctx.moveTo(i, y);
ctx2.moveTo(i, y2); }
else
{
ctx.lineTo(i, y);
ctx2.lineTo(i, y2);
}
}
ctx.stroke();
ctx2.stroke();
}
function UpdateGraph()
{
var kp = Number($("#KpVal").val())
var kd = Number($("#KdVal").val())
var ki = Number($("#KiVal").val())
var level = Number($( "#level" ).val());
Heater(level, kp,kd,ki)
}
function CreateSlider(name, val,initialValue)
{
var v = {
range: "min",
min: 0,
max: 30*10000,
value: initialValue,
slide: function( event, ui )
{
var value = ui.value/10000
$( val ).val( value );
UpdateGraph();
}
}
$( name ).slider(v);
$( val ).val( 0 );
}
$(document).ready(function()
{
CreateSlider("#Kp", "#KpVal", 5*10000)
CreateSlider("#Kd", "#KdVal",0)
CreateSlider("#Ki", "#KiVal",0)
$( "#level" ).selectmenu({
change: function( event, data )
{
UpdateGraph();
}
});
var iniKp = 5
$('#Kp').slider('value',iniKp*10000);
$( '#KpVal').val( iniKp );
UpdateGraph();
})
</script>
<p>PID seems to be a rather magical thing. I ported the Arduino-PID-Library to javascript so you can play with the constants in a simulator and and see the results immediately. Hopefully this will make people less scared about the tuning process.</p>
In this simulator, you are Lara Croft driving a car. Using the sliders below you have to choose Kp, Ki and Kd to follow the green line as closely as possible, that is without overshooting or oscillating (so, not like now). </p>
</p>
This PID controls the accelerator/decelerator of a car. There is some drag and the vehicle has a certain mass. </p>
The X axis is time and the Y axis is the position of the car. Make sure she is at the right position at the right time</p>
</p>
Can you help her? Good luck!</p>
</p>
<label for="level">Select the level of difficulty:</label>
<select name="level" id="level">
<option value="1">Level 1: Car is on a flat surface</option>
<option value="2">Level 2: Car is downhill</option>
<option value="3">Level 2: Car is on a flat surface and the engine takes time to react</option>
</select>
</br></br>
Position:</br>
<canvas id="myCanvas" width="560" height="200" style="border:1px solid #000000;"></canvas>
</br>
PID's output (accelerator):</br>
<canvas id="myOutputCanvas" width="560" height="75" style="border:1px solid #000000;"></canvas>
</br>
<div style="width:800">
<p>
<label for="KpVal">Kp:</label> <input type="text" id="KpVal" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="Kp"></div></br>
<p>
<label for="KiVal">Ki:</label> <input type="text" id="KiVal" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="Ki"></div></br>
<p>
<label for="KdVal">Kd:</label> <input type="text" id="KdVal" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="Kd"></div></br>
</div>
</p>
<h3>Notes:</h3></br>
<ul>
<li>The car is simulated by using the following equations:</li>
<ul>
<li> x(t) = v*t + 0.5*a*t^2</li>
<li> v(t) = a*t</li>
</ul>
<li>The PID code is based in the <a href='https://github.com/br3ttb/Arduino-PID-Library'>Arduino PID Library</a> by Brett Beauregard.</li>
</ul>
</br>
<h3>Lessons learnt:</h3></br>
There are 2 types of processes.</br>
<ul>
<li> Processes that keep their last state (like in the level 1, a car on a flat road). These are called <i>integrating processes</i>, they don't need a Ki and the PID won't overshoot</li>
<li> Processes that feel an external force (car on a slope, something cooling down). These are called <i>self regulating processes</i>, they do need a Ki and they will overshoot when the external force changes </li>
</ul>
</ul>
</br>
Credits go to Brett Beauregard for his excellent library and his great explanations in the <a href='https://groups.google.com/d/forum/diy-pid-control'>diy-pid-control forum</a></br>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com11tag:blogger.com,1999:blog-6185874952918981686.post-5457567754502415032016-02-20T14:48:00.000-08:002016-04-20T04:23:11.236-07:00Monitor your fridge temperatureEver wondered how efficient your fridge is? <br /><br /><div class="separator" style="clear: both;">
Mine with a set point of 9 degrees needs to cool for 45 minutes(compressor on) and seems to keep the cold for another 45 minutes(compressor off). The temperature seems to oscillate ±1.5 degrees as you see in the pic.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSFID574gGk8LnD9WRZ7qOmbNs7bcpqy0CShHKiV1O5kQELDRbX5s8Ti2S8mEREUOVins2-_un9i7_fw6rdo5Xl84JHRfdrDHrgPP2SdkA_stFnz5aurMumaQ9QMK6pgi5dgqrquK2ELK0/s1600/fridge_cycle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSFID574gGk8LnD9WRZ7qOmbNs7bcpqy0CShHKiV1O5kQELDRbX5s8Ti2S8mEREUOVins2-_un9i7_fw6rdo5Xl84JHRfdrDHrgPP2SdkA_stFnz5aurMumaQ9QMK6pgi5dgqrquK2ELK0/s400/fridge_cycle.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
I wonder how well other people's fridges perform. Should I change it? I wish everyone was posting their data! </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is a picture of my setup:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk1zDW3yIBqZARD_9jsZj9IDMqGhj5H4Nd6dg_YUaAxxx0aygTHAJcn2dFhl3JZD7sfOxoYCDLcL3Y25VzBsWT6j4sA2JQ8MjydA2zB9GEAu7lTyc0hZazEorz0BT4TMgDPbKMddGRXUwE/s1600/WP_20160220_21_30_13_Pro%255B1%255D.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk1zDW3yIBqZARD_9jsZj9IDMqGhj5H4Nd6dg_YUaAxxx0aygTHAJcn2dFhl3JZD7sfOxoYCDLcL3Y25VzBsWT6j4sA2JQ8MjydA2zB9GEAu7lTyc0hZazEorz0BT4TMgDPbKMddGRXUwE/s400/WP_20160220_21_30_13_Pro%255B1%255D.jpg" width="400" /></a></div>
<br />
I am using a ESP8266 connected to an LM75 sensor. I am using a 5000mAh 3.7V battery connected through a step down voltage regulator to get 3.3V.<br />
<div>
<br /></div>
<div>
The device has been running for 37 hours thanks to using deep sleep. Every minute the ESP8266 was waking up, measuring the temperature, sending it to a server and then back to sleep. </div>
<div>
<br /></div>
<div>
The consumption per wake up is: 5000mAh/37h/60 = 2.25mA</div>
<div>
<br /></div>
<div>
Just for laughs I'm going to elaborate on this server, it is just an old 'HTC Desire S' cellphone that is running Debian linux. This cellphone is now my cloud and it is running 24/7, it has installed PHP, nginx, mysql, samba, minidlna, ssh, avahi, and OpenVPN so I can connect remotely and have full access to everything. </div>
<div>
<br /></div>
<div>
In order the deep sleep function I had to connect the XPD_DCDC with the reset pin, if you zoom into the ESP8266 you'll see the dirty hack (credits go to http://tim.jagenberg.info/2015/01/18/low-power-esp8266/ for the idea)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCChM9sjPl3VbljenwNQEb9dZh_bvJiqLnifSoU0evybe_sI78p-1iBTJ_UFyavYqmHwNUyNQLH33yr4eDtAlCdST5-tA3_O-G8876NFhW-zK2psjetKvAG5k-OoNHvvoMDHeiZDq527Bp/s1600/WP_20160220_23_24_39_Pro+%25282%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCChM9sjPl3VbljenwNQEb9dZh_bvJiqLnifSoU0evybe_sI78p-1iBTJ_UFyavYqmHwNUyNQLH33yr4eDtAlCdST5-tA3_O-G8876NFhW-zK2psjetKvAG5k-OoNHvvoMDHeiZDq527Bp/s320/WP_20160220_23_24_39_Pro+%25282%2529.jpg" width="320" /></a></div>
<br />
<br />
I find rather interesting what happened when the battery was running out of juice. The ESP seemed to work properly but the LM75 sensor was becoming more and more noisy<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiARS0S3MZR5Nv7UeD8AN5LEJNBA_5yPRxRiTz3-29Vy3r6TmZ7EDe7Ocjb7tmG_vwbxIFVxCCYHzDLqwfFOaHEU_F2uuAkjVXqwiIYhC2wPiMjp6gCJFyFMJsfkUEVh0ZFCgqjHE3L8fJI/s1600/fridge_ESPrunningOutOfBatteries.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiARS0S3MZR5Nv7UeD8AN5LEJNBA_5yPRxRiTz3-29Vy3r6TmZ7EDe7Ocjb7tmG_vwbxIFVxCCYHzDLqwfFOaHEU_F2uuAkjVXqwiIYhC2wPiMjp6gCJFyFMJsfkUEVh0ZFCgqjHE3L8fJI/s400/fridge_ESPrunningOutOfBatteries.png" width="400" /></a></div>
<br />
One would expect that the ESP would be the first one to notice the lack of power! The time stamps are generated in the server so this seems to imply that the ESP was doing its job at the right intervals.<br />
<br />
If people show enough interest I will tidy up the code and upload it to github.</div>
Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com2tag:blogger.com,1999:blog-6185874952918981686.post-50441048232321781542015-09-13T17:06:00.002-07:002016-10-02T17:33:27.997-07:00Hacking an electronic price display, success!!Somehow I found one of this tags (don't ask) and decided to hack it. The display is WF021-01 and you can find eink's datasheet <a href="http://wenku.baidu.com/view/ff0730ee9b89680203d825a2.html">here</a>. Unfortunately this doc it in incomplete and it doesn't show the list of commands to control the display. Luckily I found many similar datasheets from other similar eink displays and noticed that many of those commands are the same across devices. I tried some of those commands and found the ones that work with my display. Tadaaa!<br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5f1IzRucgbn1J4HV36EkjQkEmHFezCrNIRZqcUGl0WboixJqb83bupvcxx1ueRATm42dD_FUa4d93icyq6sg70iWrIMDDu_NrkzFJZCQsrkcywFX7Df3KTeZHEPzJkYp5o4lQ7qiIpe0y/s1600/Delhaize_eink_price_tab.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5f1IzRucgbn1J4HV36EkjQkEmHFezCrNIRZqcUGl0WboixJqb83bupvcxx1ueRATm42dD_FUa4d93icyq6sg70iWrIMDDu_NrkzFJZCQsrkcywFX7Df3KTeZHEPzJkYp5o4lQ7qiIpe0y/s400/Delhaize_eink_price_tab.jpg" width="400" /></a></div>
<br />
<br />
<br />
This is how the back of the device looks like:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCB_V1DuRfmW_CneWFMWcVdg8xpXF3Y5Mj-bGk-Yxih1HbjvWmkXr1zHS1hsR64yFr1S3amTHNdMMII1eZCOxI1RRlutWra0zXdtFbsTVUHEFsAEfMYY6RSbZ2tEqN5bwvLTBOBPM5iE-O/s1600/WP_20150906_23_31_02_Pro.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCB_V1DuRfmW_CneWFMWcVdg8xpXF3Y5Mj-bGk-Yxih1HbjvWmkXr1zHS1hsR64yFr1S3amTHNdMMII1eZCOxI1RRlutWra0zXdtFbsTVUHEFsAEfMYY6RSbZ2tEqN5bwvLTBOBPM5iE-O/s400/WP_20150906_23_31_02_Pro.jpg" width="400" /></a></div>
<br />
<div class="" style="clear: both; text-align: left;">
<br /></div>
<div class="" style="clear: both; text-align: left;">
I cant tell much about the epoxy blob, luckily the PCB has a bunch test pads that can be used to drive the display (I had to cut the traces to stop the main processor from interfering with my data):</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
This is what each test pad is for:</div>
<div style="text-align: left;">
<div style="text-align: center;">
<br />
<ul><br />
<li style="text-align: left;">tp11: bs1(set this oen to ground so you can use the 3 wire interface a)</li>
<li style="text-align: left;">tp10: res</li>
<li style="text-align: left;">tp8 : d/c (no need to drive this one if you set tp11 to ground)</li>
<li style="text-align: left;">tp7: busy</li>
<li style="text-align: left;">tp6: cs</li>
<li style="text-align: left;">tp5: d0</li>
<li style="text-align: left;">tp4: d1</li>
<li style="text-align: left;">tp1: vddi</li>
<li style="text-align: left;">tp18: gnd </li>
</ul>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;"></span></div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span><span style="font-family: "courier new" , "courier" , monospace;"></span>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span><span style="font-family: "courier new" , "courier" , monospace;"></span>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span><span style="font-family: "courier new" , "courier" , monospace;"></span>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span><span style="font-family: "courier new" , "courier" , monospace;"></span>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span>
</div>
<div style="font-size: small;">
<span style="font-family: "courier new" , "courier" , monospace;">
</span><span style="font-family: "courier new" , "courier" , monospace;"></span></div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span><div style="font-size: small;">
</div>
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div>
<br /></div>
<div>
I am using an arduino to talk to the eink display, I'll post the code to drive it as soon as I clean it up a bit. Enjoy!</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com4tag:blogger.com,1999:blog-6185874952918981686.post-49063705900472201502015-06-23T15:37:00.000-07:002016-09-07T02:48:35.939-07:00Simple nodemcu module to drive a nokia LCD (PCD8544)<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
I desperately wanted to hook a Nokia5110 LCD to my ESP8266/nodemcu. I wrote a LUA module but it was slow and it was taking too much memory, mainly because the font data needs to stay in the precious RAM. <br />
<br />
It looks like anything I do ends up taking too much memory, so the way to go is to write modules in c and then invoke them from LUA. I am very pleased with the results, so here it is for you to use: <a href="https://drive.google.com/file/d/0B4IJZPdCtzO0dUsweHBDS2QxbTg/view?usp=sharing">Download</a> (just for fun the lua module and the image are also included)</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSFoFr-x5EiNxLSfdcNgIH7fljmjrZv-Iv2t4qlh6CzHyCJmV53Uph6zdJkf90bfJ1XBBtZHjseYJ5jbakuWOLlxjZCFGuVhZLDr4_E6Go5wU5Oixpfom7oedh_vCiiUPsLXdzrV8J4T0p/s1600/outrun_lcd.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSFoFr-x5EiNxLSfdcNgIH7fljmjrZv-Iv2t4qlh6CzHyCJmV53Uph6zdJkf90bfJ1XBBtZHjseYJ5jbakuWOLlxjZCFGuVhZLDr4_E6Go5wU5Oixpfom7oedh_vCiiUPsLXdzrV8J4T0p/s320/outrun_lcd.png" /></a></div>
<div style="text-align: left;">
<br />
<div>
You can use it this way:</div>
<div style="orphans: auto; text-align: left; text-indent: 0px; widows: 1;">
<ul>
<li>pcd.init()</li>
<li>pcd.locate(0,0)</li>
<li>pcd.print("Hello world!")</li>
</ul>
<div>
And if you want to display images you can do it this way:</div>
<div>
<ul>
<li>pcd.init() </li>
<li>file.open("image.bin", "r") </li>
<li>pcd.printbin(file.read()) </li>
<li>file.close()</li>
</ul>
<div>
I already sent a pullrequest to the nodemcu guys, it may not get accepted as the pins needed are hardcoded :/ </div>
</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
</div>
</div>
</div>
Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com8tag:blogger.com,1999:blog-6185874952918981686.post-14086124773815304222013-10-05T04:32:00.002-07:002013-10-05T04:39:25.059-07:00Software defined FM radio transmitter (Arduino + AD9850)This video shows it all, take it away!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='472' height='266' src='https://www.youtube.com/embed/gbsZkoI-380?feature=player_embedded' frameborder='0'></iframe></div>
<br />
The frequency is generated by the AD9850 and the modulation is done by the arduino<br />
<br />
The full code is here:<br />
<a href="http://pastebin.com/YMErwwK3">http://pastebin.com/YMErwwK3</a><br />
<br />
The FM band channels are centered at certain frequency, in our case 90Mhz, any slight deviation of that freq (by a max of +/- 75Khz) will move the membrane of the speaker backward or forward, here is the bit of code that implements that.
And this is the (unoptimized) modulation routine.<br />
<pre class="prettyprint">void playTone(unsigned int note, unsigned int duration )
{
const double freq = 90 * 1e6; // transmitting at 90Mhz
// play silence
if ( note == 0)
{
ad.setfreq(freq);
delay(duration);
return;
}
unsigned long currentMillis = millis() + duration;
while( millis()< currentMillis)
{
ad.setfreq(freq + 75e3/2); // speaker's membrane backward
delayMicroseconds(note);
ad.setfreq(freq - 75e3/2); // speaker's membrane forward
delayMicroseconds(note);
}
ad.setfreq(freq );
}
</pre>
<br />
Credits go to:<br />
Brett Hagman for the RTTTL tune player<br />
Poul-Henning Kamp for the AD9850 lib<br />
<div>
<br /></div>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com7tag:blogger.com,1999:blog-6185874952918981686.post-89712324402476806512013-07-05T03:51:00.001-07:002013-07-07T04:35:31.419-07:00Minimal ECG using an Arduino and Xoscillo<div class="separator" style="clear: both; text-align: left;">
First off, the picture :)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFpKe1s1NV2SaIGj5ZneUZBdDXyMAofhWGIeA1TmR3sZjMZp-VW4SkoJlxOkURAOIjY9JPSOLyf1Muf-dpMIUFWNMuu5c_EdE1-h5zAgfsi1jay2WFKt_rzh5zk-qxPyq4TUIACm2F_Hqs/s853/heartbeat4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFpKe1s1NV2SaIGj5ZneUZBdDXyMAofhWGIeA1TmR3sZjMZp-VW4SkoJlxOkURAOIjY9JPSOLyf1Muf-dpMIUFWNMuu5c_EdE1-h5zAgfsi1jay2WFKt_rzh5zk-qxPyq4TUIACm2F_Hqs/s320/heartbeat4.png" width="320" /></a></div>
To display the wave I am using <a href="https://code.google.com/p/xoscillo/" target="_blank">XOSCILLO</a>, a very cool and open source tool (which I wrote :P) that converts your Arduino into an oscilloscope.<br />
<br />
<b>Circuit diagram</b><br />
<br />
Here is the scheme, I am using the typical instrumental amplifier(ins amp) and then another op amp to get some more gain. An ins-amp is like an op-amps but with a huge CMRR, I am using a AD8221 which comes in a tiny small package, it's lead pitch is only 0.65mm, if you want to know what I did to create a simple breakout board please follow this <a href="http://codinglab.blogspot.be/2013/06/poor-mans-msop-soldering.html" target="_blank">link</a>.<br />
<br />
I'm using a single supply for the amps that comes from the arduino 5V pin, and I am creating a buffered virtual ground, this is really important.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgME8udidtF9bZgXRdseFyo8x_pfixchnP-ei8Z4nUEA9e-YakDmWQ0jqyXgX8wrVfNn32-FxVoQxQVDVuekQlXsUmgKRBPBYFHhvRmBNR6wajPyoL3XSga2CvaywTPJ1uvUhdlWXIGaizw/s1600/IMAG0949.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgME8udidtF9bZgXRdseFyo8x_pfixchnP-ei8Z4nUEA9e-YakDmWQ0jqyXgX8wrVfNn32-FxVoQxQVDVuekQlXsUmgKRBPBYFHhvRmBNR6wajPyoL3XSga2CvaywTPJ1uvUhdlWXIGaizw/s320/IMAG0949.jpg" width="320" /></a></div>
<br />
Here is, a bit dark, a pic of the setup in the breadboard.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirBI4gtdLuT8k5MrteYrqloepMAZPRbGuqi3DKNDpppOAsGX0ZgCEJWUBIIq3LmdZ47F5TBVJAOc2oRU2a3eu1ACHvMw5LZ5Eldr_AhxI887vfYJl_cXltkvlHiwJZ9-WU3P7pEcPgWcGP/s1600/IMAG0940.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirBI4gtdLuT8k5MrteYrqloepMAZPRbGuqi3DKNDpppOAsGX0ZgCEJWUBIIq3LmdZ47F5TBVJAOc2oRU2a3eu1ACHvMw5LZ5Eldr_AhxI887vfYJl_cXltkvlHiwJZ9-WU3P7pEcPgWcGP/s320/IMAG0940.jpg" width="320" /></a></div>
<br />
<b>Tricks of the trade:</b><br />
<br />
This is what makes the difference between a working ECG and a non working one :)<br />
<br />
The main problem is that the device is so sensitive that it get interference from almost everywhere, specially the mains hum at 50hz). As you can see I got a clean signal, and I am not using any kind of serious filtering, note that xoscillo has a low pass filter and I am not even using it, so what are the tricks?<br />
<br />
<ol>
<li>Run it from a laptop and unplug the charger!</li>
<li>Don't use a second monitor, the HDMI port will cause all sorts of high frequency interferences</li>
<li>Get about 1 meter away from the laptop</li>
<li>Buy some serious ECG electrodes, mines are "<span style="text-decoration: underline;">H124SG </span>* Ø 24 mm", they come in a box of 50 and should cost about 11 euros. </li>
</ol>
<br />
That's all, if you like it or build it or need help feel free to write a comment, it will encourage me to write more articles :)<br />
<br />
<br />
<br />Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com37tag:blogger.com,1999:blog-6185874952918981686.post-52677054712474498952013-06-22T14:54:00.001-07:002013-06-22T14:57:45.572-07:00Poor man's MSOP soldering<div class="separator" style="clear: both; text-align: left;">
MSOP stands for Mini Small Outline Package, that means that width of 4 leads is just 2mm, exactly the width of a row in a stripboard... Let see how can we solder that though.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
On a piece of wood we tape carefully 4 thin wires. We start my taping one wire and then taping again a second one at a distance of 2mm, take as much time as you need, this step is crucial, place on top the MSOP to make sure they have the right separation. If you need to make any adjustments use the blade of a cutter to move the wire. Good now you have the top one and the lower one. For the 2 inner ones, just put them in between and fix them with tape, then use the cutter blade to make sure they are all spaced equally</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWfF85Bq0KotL03cHFxQ-LAaJ8N7jRBje3ptPfkjoh8eDAesYoD8a2cbAErRGJIZrc7hwfvlOQaO0F68UekSOeDtGJW3JXOwNfBq8NilntWJN4o_2D9MLF5RKCxqOkoHENfRysXuyOkRLE/s1600/IMAG0929.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWfF85Bq0KotL03cHFxQ-LAaJ8N7jRBje3ptPfkjoh8eDAesYoD8a2cbAErRGJIZrc7hwfvlOQaO0F68UekSOeDtGJW3JXOwNfBq8NilntWJN4o_2D9MLF5RKCxqOkoHENfRysXuyOkRLE/s320/IMAG0929.jpg" width="320" /></a></div>
<br />
We place the MSOP on top and we tape it, then make the necessary adjustments in the separations of the wires. Once we are happy we tape the IC this time more tightly.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMDk3M_w3R7ghKztMk3NHHVh9-SIki6lk15uaSUeqAQww71qgk62pnHhaHoPDE7BYJ43AbINE1A4Sfw87eu1yjT5mJ_hyn0pxNeLOYrXnUfO6HkLIe2ovaxpsdyCBoaOntIG9TFxdJvXwU/s1600/IMAG0930.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMDk3M_w3R7ghKztMk3NHHVh9-SIki6lk15uaSUeqAQww71qgk62pnHhaHoPDE7BYJ43AbINE1A4Sfw87eu1yjT5mJ_hyn0pxNeLOYrXnUfO6HkLIe2ovaxpsdyCBoaOntIG9TFxdJvXwU/s320/IMAG0930.jpg" width="320" /></a></div>
Time to solder, use flux and apply the iron firmly as with any other SMD<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7MQ2lWjqcrq3EqymotBlEm1DszdKL9yREmAMQIVUJQQXM_f4yyz6t439bi1acj_BBxllIqhfoaU-WBtwTYSRs20OXarPAPz7EM5RmjQSaajhQAUkfqJYAOxsbHnM7nSU08f78Fb7bRpR7/s1600/IMG_0455.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7MQ2lWjqcrq3EqymotBlEm1DszdKL9yREmAMQIVUJQQXM_f4yyz6t439bi1acj_BBxllIqhfoaU-WBtwTYSRs20OXarPAPz7EM5RmjQSaajhQAUkfqJYAOxsbHnM7nSU08f78Fb7bRpR7/s320/IMG_0455.JPG" width="320" /></a></div>
Once we have one side done we do the other side, this time it will be easier since the other half is firmly fixed, time to correct the separation of the wires too.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij_aVUpc6i_yoNCH-NX_if7DQ36yWic-EKEQRR52Flc5DecG_tC5LEFame4azpyyYSBWEaqzJPCuW_eeZICZMmWLlJGunqZgnfcXMhUC4ITcNGP3iMWQOvBG1ty_5mqaYrRm4Z7x0ti7iZ/s1600/IMG_0457.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij_aVUpc6i_yoNCH-NX_if7DQ36yWic-EKEQRR52Flc5DecG_tC5LEFame4azpyyYSBWEaqzJPCuW_eeZICZMmWLlJGunqZgnfcXMhUC4ITcNGP3iMWQOvBG1ty_5mqaYrRm4Z7x0ti7iZ/s320/IMG_0457.JPG" width="320" /></a></div>
Once we remove the tape we check the back of the IC to make sure all looks good and clean.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaQcvZtywDrOP3UNXrg5O22R_nxC-rYNkZ9sn2Bjtv1ZapCgX62zhqr1NlH5SdgREPcmzDfupa_GuX_aGMIZC3VoUQnBRbbxqvjngzLQdRnx3iENjVLJRYIJ-cjGJ62Y9tuFxahe3xwhW-/s1600/IMG_0458.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaQcvZtywDrOP3UNXrg5O22R_nxC-rYNkZ9sn2Bjtv1ZapCgX62zhqr1NlH5SdgREPcmzDfupa_GuX_aGMIZC3VoUQnBRbbxqvjngzLQdRnx3iENjVLJRYIJ-cjGJ62Y9tuFxahe3xwhW-/s320/IMG_0458.JPG" width="320" /></a></div>
We cut the thin wires by just applying some firm vertical pressure with a cutter.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwgOkYYRsrHz04tOqBoubfn-kAxoIxBeMrb2hSD1dDEbDfhZZouFYN6a-rbrv2uHpLib9jVM8yKTMzEaEBwxQllYzDrAi5eJtzEPus4IB3Q_ZYS0UNu_mEs6qbhHEmqv8kiFcNjGhygu9r/s1600/IMG_0460.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwgOkYYRsrHz04tOqBoubfn-kAxoIxBeMrb2hSD1dDEbDfhZZouFYN6a-rbrv2uHpLib9jVM8yKTMzEaEBwxQllYzDrAi5eJtzEPus4IB3Q_ZYS0UNu_mEs6qbhHEmqv8kiFcNjGhygu9r/s320/IMG_0460.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtaSz71tYdxQIO5QGHWxJNxtm6Ohbju3n4Z04nPRnGDNWjOQxuTT7EmffVP-A0E4QgDth5JDRlxO1E5_Dgkd6mDMlwyNz0aUqnyZ7d98lzaf4dGMSCHoHL7tHL1pLoWJL1gNFwU9WWJHT0/s1600/IMG_0461.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtaSz71tYdxQIO5QGHWxJNxtm6Ohbju3n4Z04nPRnGDNWjOQxuTT7EmffVP-A0E4QgDth5JDRlxO1E5_Dgkd6mDMlwyNz0aUqnyZ7d98lzaf4dGMSCHoHL7tHL1pLoWJL1gNFwU9WWJHT0/s320/IMG_0461.JPG" width="320" /></a></div>
Time to place it on the stripboard, we carefully separate the wires and we insert them through the holes,<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGfzD_Fb9wEeYLi4d4opiO9mQMmr-NX5ZLv9BBLvgX4b81qA8T7ZfqkmLnLv9Pmw6LeWNfxVNv9C-sSBCWJ6j84m-DZRqEe_I6wuDLHUWEEOoPGE1em50ZyEkbRKIaqTRoleqkjgEGGV29/s1600/IMG_0463.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGfzD_Fb9wEeYLi4d4opiO9mQMmr-NX5ZLv9BBLvgX4b81qA8T7ZfqkmLnLv9Pmw6LeWNfxVNv9C-sSBCWJ6j84m-DZRqEe_I6wuDLHUWEEOoPGE1em50ZyEkbRKIaqTRoleqkjgEGGV29/s320/IMG_0463.JPG" width="320" /></a></div>
And voila, the breakout board :)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWCnAPX6f6YjyX4vDlUCgUkdPfhBs9G_VrHsyXzjRuhBrZ-93-IVPLBrwEDwQso2rndiibceA4ZAXocafXdPwBA-BiFXLkPXnpRCJPB3Cwkflu4aQvP7FpaXBrlqzX2IzP_JeqL4-MCbZg/s1600/IMG_0465.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWCnAPX6f6YjyX4vDlUCgUkdPfhBs9G_VrHsyXzjRuhBrZ-93-IVPLBrwEDwQso2rndiibceA4ZAXocafXdPwBA-BiFXLkPXnpRCJPB3Cwkflu4aQvP7FpaXBrlqzX2IzP_JeqL4-MCbZg/s320/IMG_0465.JPG" width="320" /></a></div>
<br />Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com17tag:blogger.com,1999:blog-6185874952918981686.post-44276085453154759622013-02-26T11:18:00.000-08:002013-02-27T14:22:22.846-08:00Measuring inductances using an arduino<br />
I just read this excellent article about measuring inductances:<br />
<br />
<a href="http://reibot.org/2011/07/19/measuring-inductance/">http://reibot.org/2011/07/19/measuring-inductance/</a><br />
<br />
The technique consists in measuring the resonance frequency of a LC circuit. Since this frequency is:<br />
<br />
<div style="text-align: left;">
f = 1.0/(2.0*M_PI*sqrt(L*C))</div>
<br />
By measuring f with the arduino and knowing C you can easily get L.<br />
<br />
I modified the code so its much more precise, the original code is using 'pulse' to read half an oscillation. My code instead measures one whole oscillation by using an AVR's hw feature called Input Compare, this feaure starts and stops a timer that runs at 16Mhz.<br />
<br />
Enjoy!<br />
<br />
<br />
<pre class="prettyprint">//measuring inductance using the higher precision input compare
//based on http://reibot.org/2011/07/19/measuring-inductance/
//capture Flag
volatile uint8_t Flag;
void InitTimer1(void)
{
cli();
//Set Initial Timer value
TCCR1A = 0;
TCCR1B = 0;
// Input Capture Noise Canceller
TCCR1B |= (1 << ICNC1);
//First capture on rising edge
TCCR1B |= (1 << ICES1);
//Start timer without prescaller
TCCR1B &= ~ ((1 << CS12) | (1 << CS11) | (1 << CS10));
TCCR1B |= (1 << CS10);
//Enable input capture and overflow interrupts
TIMSK1 = 0;
TIMSK1 |= (1 << ICIE1) | (1 << TOIE1);
Flag = 0;
sei();
}
volatile uint16_t Capt;
volatile uint16_t T1Ovs2;
//capture ISR
ISR(TIMER1_CAPT_vect)
{
if (Flag == 0)
{
//reset overflows
TCNT1 = 0;
T1Ovs2 = 0;
}
else if (Flag == 1)
{
Capt = ICR1;
//disable capture and overflow interrupts
TIMSK1 &= ~ ((1 << ICIE1) | (1 << TOIE1));
//clear pending interrupts
TIFR1 = (1 << ICF1) | (1 << TOV1);
}
//increment Flag
Flag++;
}
//Overflow ISR
ISR(TIMER1_OVF_vect)
{
T1Ovs2++; //increment overflow counter
}
//13 is the input to the circuit (connects to 150ohm resistor)
//8 is the comparator/op-amp output.
//reibot.org for guide
double pulse, freq, inductance;
//insert capacitance here. Currently using 2uF
double capacitance = 2E-6;
void setup()
{
Serial.begin(115200);
pinMode(8, INPUT);
digitalWrite(8, LOW);
pinMode(13, OUTPUT);
Serial.println("Why hello!");
delay(200);
}
void loop()
{
digitalWrite(13, HIGH);
delay(10); //give some time to charge inductor.
digitalWrite(13, LOW);
delayMicroseconds(15); //make sure resonance is measured
InitTimer1();
delay(100); // wait for ICR to read once cycle
pulse = (T1Ovs2 * 65536 + Capt) / 16.0;
if (pulse > 0.1)
{
freq = 1.E6 / pulse;
inductance = 1. / (capacitance * freq * freq * 4. * 3.14159 * 3.14159);
inductance *= 1E6;
Serial.print("High for uS:");
Serial.print(pulse);
Serial.print("\tfrequency Hz:");
Serial.print(freq);
Serial.print("\tinductance uH:");
Serial.println(inductance);
delay(20);
}
}</pre>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com7tag:blogger.com,1999:blog-6185874952918981686.post-20852770067550973492013-02-03T03:57:00.002-08:002013-02-03T04:04:30.812-08:00SMD if there is a will there is a wayI couldn't wait for my breakout boards to arrive! I hope this encourages others to do some smd soldering... I used some rosin soldering flux from radio shack and a regular solder.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi40V_r-U-AAZ40c5vYtDl0jBsEIu92b5TBS6ZWlVg2Hed6QaFRRAafYbjyvQbxiFUydNYEr7oN2BHLa3B5l6aNb1GknsS1IDbYpGn3ITeHbkFgJxdI82iWD1FH_qBXc4u4f7ypY3J9eTb8/s1600/IMG_0351%5B1%5D.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi40V_r-U-AAZ40c5vYtDl0jBsEIu92b5TBS6ZWlVg2Hed6QaFRRAafYbjyvQbxiFUydNYEr7oN2BHLa3B5l6aNb1GknsS1IDbYpGn3ITeHbkFgJxdI82iWD1FH_qBXc4u4f7ypY3J9eTb8/s400/IMG_0351%5B1%5D.JPG" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">SMD breakout board</td></tr>
</tbody></table>
<br />Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com2tag:blogger.com,1999:blog-6185874952918981686.post-45806500661719104942013-01-16T15:44:00.001-08:002013-03-11T02:21:19.730-07:00Virtual MSX disk drive<br />
When I was a kid I had an MSX, a SVI-728 to be more precise, it's just a Z80 based computer with 64Kb of RAM. Mine used cassette tapes to load games and the loading times were eternal not to mentioned all the loading errors that required restarting the load from the beginning.<br />
<br />
Other friends of mine had an MSX with a disk drive but I got still stuck with the tapes :-(<br />
<br />
So... Revenge! I decided to build my own disk unit :-)<br />
<br />
MSX's with a disk drive come with a disk BIOS that handles all the disk operations, from the lowest level (i.e.: read sector 23) to extending BASIC with new commands to list the available files in the disk, formating, deleting and creating files, and so on.<br />
<br />
My first step was to get a disk BIOS from a MSX with a disk unit and patch the sector reading/writing routine so instead of talking to a disk unit, it would talk to another device, an Arduino.<br />
<br />
Unfortunately I can't fit an 720Kb disk in an Arduino but since it has a USB connection it can ask my PC to get that sector form an certain disk image in my PC's hard's disk and send it thought the USB cable. <br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
For that I need some gluing hardware between the MSX and the Arduino, here is the pic of the setup</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj40WBomuE1pTCrocvziuKYoQhQeIWZ6l5nyfrMIPRB5bwPJrLxew7YPDbNjdjHf9t1hCsKtdWfwOmabN0zA8A7npjx5OrOFpKC8_q2WSRZogUD7Jr1a9Ktrd0Hg_9Wmv6cQaIiq5uODIKb/s1600/IMAG0723.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj40WBomuE1pTCrocvziuKYoQhQeIWZ6l5nyfrMIPRB5bwPJrLxew7YPDbNjdjHf9t1hCsKtdWfwOmabN0zA8A7npjx5OrOFpKC8_q2WSRZogUD7Jr1a9Ktrd0Hg_9Wmv6cQaIiq5uODIKb/s400/IMAG0723.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Breadboard with arduino-msx gluing logic</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And here are the schematics of the interface:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcZCSZiIKGRG728DSQDxCTncLvReivuoMUIqpymKTVgez_LGnqNT1zPV_iFvrb-f8L_JZXj8dNMzKPpSZimwYlZboTP4lU-JZTYTRHS25EzGvTDn9arwllCSRiqnCOvimt2MqgEcCOPAh2/s1600/IMAG0730-1.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcZCSZiIKGRG728DSQDxCTncLvReivuoMUIqpymKTVgez_LGnqNT1zPV_iFvrb-f8L_JZXj8dNMzKPpSZimwYlZboTP4lU-JZTYTRHS25EzGvTDn9arwllCSRiqnCOvimt2MqgEcCOPAh2/s400/IMAG0730-1.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Schematics</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
The trick of the trade</h3>
<div class="separator" style="clear: both; text-align: left;">
It all works thanks to the Z80's /WAIT pin, when an <i>IN</i> or an <i>OUT</i> instruction happens for an port below 31 the logic gates put this pin to a low sate making the Z80 wait, the Arduino notices that and can fetch the data from the computer and put it onto the 74245 buffer, then the Arduino will raise the /WAIT pin to make the Z80 resume the execution so the OUT instruction gets the data from the buffer.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
The software bit on the MSX side...</h3>
<div class="separator" style="clear: both; text-align: left;">
</div>
My computer didn't have a disk BIOS so I had to get one, fortunately Arjen Zeilemaker had disassembled some and put the asm code in <a href="http://sourceforge.net/projects/msxsyssrc/" target="_blank">sourceforge</a>. All I had to do was to write the DSKIO function to talk with my arduino, the code was so simple that I just used notepad and worked on the second run. I took a game cartridge and replaced the game's ROM with an 16Kb EEPROM I got from EBAY. As for writing the EEPROM I used a reader/writer I built once as a quick hack, I used for that a ATMEGA128 since it has enough pins to driver teh 28 pins you need to set in order to write or read an EEPROM.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2urR_3MHZAAMG-ydhx7GP54LIhbLcGME878zpk7GIjwsxQUo2pHRVZQ2Tmbg1kG5mQNd3LwiP_9Jz58rjzf0HjZ_pB3kSWwzcgHvKdNLBn7BgAPLMlrpVGCDT-j4GhxjaHH_HUQRNZGlc/s1600/IMAG0710.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2urR_3MHZAAMG-ydhx7GP54LIhbLcGME878zpk7GIjwsxQUo2pHRVZQ2Tmbg1kG5mQNd3LwiP_9Jz58rjzf0HjZ_pB3kSWwzcgHvKdNLBn7BgAPLMlrpVGCDT-j4GhxjaHH_HUQRNZGlc/s400/IMAG0710.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Simple flash memory reader on the top, game cartridge on the bottom</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both;">
The two white cables sticking out of the Atmega128 are the serial port, I wont tell what are the black and red ones :-)</div>
<h3>
..and on the PC side</h3>
<div>
I just used Python to read the commands coming from them MSX, the script will take the 512 bytes sector and will send it to the arduino and 1Mbit per second. The Arduino will send byte by byte to the Z80 at a similar speed.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDpxrzqxBWiItvN227tS7hogbnytIPISFx_EtMRWlWy6u18Dm89wvwLbfccqWLq_hMHbZrZJRColnadZttUOUwisSm5yp2KdKQ5kBrmkAlJmgDICR-nkWryTMBTZNOWXGmy6cxcNPn0Woy/s1600/virtualdisk.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDpxrzqxBWiItvN227tS7hogbnytIPISFx_EtMRWlWy6u18Dm89wvwLbfccqWLq_hMHbZrZJRColnadZttUOUwisSm5yp2KdKQ5kBrmkAlJmgDICR-nkWryTMBTZNOWXGmy6cxcNPn0Woy/s400/virtualdisk.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is the video, sorry for the shaky hand :-) On the left you have the python script, on the right VLC media player.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/i4hw8YQkgYM?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<h3>
Source code! :)</h3>
<div>
</div>
<br />
Ok here are the sources, sorry I didn't document the code so much, please let me know if you have any questions.<br />
<a href="https://docs.google.com/file/d/0B4IJZPdCtzO0OGJvcnB3U0xnY1U/edit?usp=sharing">https://docs.google.com/file/d/0B4IJZPdCtzO0OGJvcnB3U0xnY1U/edit?usp=sharing</a></div>
Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com16tag:blogger.com,1999:blog-6185874952918981686.post-32567904061336138922011-10-06T17:12:00.000-07:002013-01-16T16:12:37.385-08:00DIY Linear actuator out of scanner parts and a drawer sliderTo build this linear actuator I stripped off from a scanner the motor + gears along with the timing belt and the pulley. I bought in Brico a cheap drawer slider and screwed it all into a piece of wood.<br />
<br />
First the video showing off what all this is about<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/4xdWUbPyF18?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />
Below you can find a pic of one end of the actuator:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.flickr.com/photos/raul_aguaviva/6218915154/" style="margin-left: 1em; margin-right: 1em;" title="IMAG0336 by raul_aguaviva, on Flickr"><img alt="IMAG0336" nbsp="nbsp" src="http://farm7.static.flickr.com/6220/6218915154_4304b3134b.jpg" width="400" /></a></div>
<br />
<br />
As you can see, I attached the stepper to the piece of wood by just using a wire, and it works great!<br />
Also note that zigzag piece of metal that links the timing belt with the drawer rail. In the picture below you can see it in more detail<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.flickr.com/photos/raul_aguaviva/6218916182/" style="margin-left: 1em; margin-right: 1em;" title="IMAG0337 by raul_aguaviva, on Flickr"><img alt="IMAG0337" src="http://farm7.static.flickr.com/6220/6218916182_f7fc1bff03.jpg" width="400" /></a></div>
<br />
<br />
The timing belt is sandwiched between two pieces of metal.<br />
<br />
And finally below you can see the pulley at the other end, this was a tricky part, keep reading more the details!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.flickr.com/photos/raul_aguaviva/6218917202/" style="margin-left: 1em; margin-right: 1em;" title="IMAG0338 by raul_aguaviva, on Flickr"><img alt="IMAG0338" src="http://farm7.static.flickr.com/6056/6218917202_c91c06f9c6.jpg" width="400" /></a></div>
<br />
<br />
This pulley had an axis that was riveted to the chassis of the scanner, I pulled it off with my pliers and welded it into a screw using solder, I had to heat both parts for a long time before in order to get the solder to bind both parts, the picture below shows the results:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.flickr.com/photos/raul_aguaviva/6218939668/" style="margin-left: 1em; margin-right: 1em;" title="IMAG0344 by raul_aguaviva, on Flickr"><img alt="IMAG0344" src="http://farm7.static.flickr.com/6223/6218939668_83867a8a43.jpg" width="400" /></a></div>
<br />
<br />
And voila, its working better than I expected! Keep tuned for more and thanks for reading!<br />
<br />
BTW greetings goes to the guys in <a href="http://www.blogger.com/www.timelab.org/">timelab</a> for inspiring me! Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com8tag:blogger.com,1999:blog-6185874952918981686.post-86081984435375298452011-09-17T11:28:00.000-07:002011-10-06T16:44:44.463-07:00A Pre Amp for an electric guitarI bought an electric guitar and needed an amp, I thought is was kind of silly to buy one since I could use my computer speakers. You cannot connect the guitar to the computer amp directly since the signal coming from the guitar is too weak, you need a preamp.<br />
<br />
I had a bunch of 741 op amps around and decided to build a preamp myself. I used a inverter amp configuration (quite a simple one) and it worked great. By cranking up the gain by a lot I get a nice heavymetal distortion.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPm3fY2Jzu_MCZ8KTAtAziuX0szxdwWJbmV0JEC9ERbpFkOBvk3vu6jx9lrKBXLjpKj8qnen_3Od-PDQ2JoWorhtRbfAC6VeqQBhB6-MtnUZJZce1T6ovyG64c6deaC9hBlVtl5dJ-3Ut/s1600/IMAG0287.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5653401533723583634" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPm3fY2Jzu_MCZ8KTAtAziuX0szxdwWJbmV0JEC9ERbpFkOBvk3vu6jx9lrKBXLjpKj8qnen_3Od-PDQ2JoWorhtRbfAC6VeqQBhB6-MtnUZJZce1T6ovyG64c6deaC9hBlVtl5dJ-3Ut/s400/IMAG0287.jpg" style="cursor: hand; cursor: pointer; display: block; height: 240px; margin: 0px auto 10px; text-align: center; width: 400px;" /></a><br />
<br />
<br />
Here is the schematic along with a link to see it running in a free java circuit simulator.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga9sYjTN5Wkpf-4Bw5Ggt-Y5484t0UDJeCavFlWncf5rDKD2SqGQiOAcnByj8-AXoq5YN9BA2fZSbjB0lkwDbOdKTxfKx4uG425rJcyLrMweRofn3ieGJUuRGh8f7bhZd1lt8yAj6GDS3X/s1600/guitar_preamp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga9sYjTN5Wkpf-4Bw5Ggt-Y5484t0UDJeCavFlWncf5rDKD2SqGQiOAcnByj8-AXoq5YN9BA2fZSbjB0lkwDbOdKTxfKx4uG425rJcyLrMweRofn3ieGJUuRGh8f7bhZd1lt8yAj6GDS3X/s320/guitar_preamp.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.falstad.com/circuit/#%24+1+5.0E-6+10.20027730826997+86+5.0+43%0Aa+224+176+400+176+0+15.0+-15.0+1000000.0%0Ar+224+80+400+80+0+100000.0%0Ac+224+32+400+32+0+1.0E-10+-0.06031512213234991%0Ar+128+160+224+160+0+1000.0%0Ac+64+160+128+160+0+1.0E-6+2.5436479540585813E-4%0Ac+400+176+480+176+0+1.0E-6+1.1262796251187979E-12%0Aw+224+160+224+80+0%0Aw+224+80+224+32+0%0Aw+400+32+400+80+0%0Aw+400+80+400+176+0%0Ag+224+192+224+272+0%0AR+64+160+32+160+0+1+440.0+0.001+0.0+0.0+0.5%0Aw+480+176+512+176+0%0Ax+488+209+520+214+0+20+Out%0Ax+8+202+62+207+0+20+Guitar%0Ao+11+64+0+35+0.0048828125+9.765625E-5+0+-1%0Ao+12+64+0+35+0.15625+4.8828125E-5+1+-1%0A">Click here to see it running in a Circuit Simulator (needs Java)</a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
The only problem is that the preamp seems to amplify too an FM radiostation and I can hear some nice music while I play guitar....<br />
<div>
<br /></div>
<div>
At the beginning I thought my guitar was haunted by The Beatles and played on its own, when I hard a kind of a voice I suspected it could be receiving some sort of radio signal.. </div>
<div>
<br /></div>
<div>
You don't believe me? Check out this video! </div>
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/GSn_zrsMqXE/0.jpg"><param name="movie" value="http://www.youtube.com/v/GSn_zrsMqXE?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" />
<param name="bgcolor" value="#FFFFFF" />
<embed width="320" height="266" src="http://www.youtube.com/v/GSn_zrsMqXE?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash"></embed></object></div>
<div>
<br /></div>
<br />
<br />Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com1tag:blogger.com,1999:blog-6185874952918981686.post-33739592316931343912011-09-17T10:50:00.000-07:002011-09-17T11:23:34.031-07:00Gameboy Cart Using an AVRBuilt a Game Boy flash cart using an AVR. Took a cartridge I bought for a few euros and replaced the ROM chip with a 32Kb RAM I took from a printer. The pinout of most RAM, ROM and EEPROM chips are almost the same, I was quite glad about this :-)<br /><br />The next step was to find a processor that had many free pins to drive the 15 for the address bus and 8 for the data bus, for that then I used and AVR128.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyhLvooWWfAgTPP1ve8h4ShUZX5RboQkbBnpC2eKKLA1s6hLlIKkqEEFAMRzTwmEy-2I_JmBrhgLxefLPlgxLTf8zo8Ee4PDQymuF886BR1x5dxOXAaariyLDzQavQhmtJx1AwfPhp0DDO/s1600/IMAG0299.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 240px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyhLvooWWfAgTPP1ve8h4ShUZX5RboQkbBnpC2eKKLA1s6hLlIKkqEEFAMRzTwmEy-2I_JmBrhgLxefLPlgxLTf8zo8Ee4PDQymuF886BR1x5dxOXAaariyLDzQavQhmtJx1AwfPhp0DDO/s400/IMAG0299.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5653388257062814402" /></a><br /><br />If you look at the cartridge 'pins', you'll see a cable soldered to one of them, that is the HALT line of the Z80, controlling this pin I can freeze the Z80, this way the data and addresses buses are free and my AVR can write and read data from my RAM.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIy_NDhO_IFKWUMIz55XDrmWR7KpvC3gSibWm6p_KGEGDzKurUZyEv3YhMPYALIdL7vnPOajkBCLFS9VcETiOQZ-VJ-jmel0Krk2lVcvqfxyivuPOuAfClmB4HgrYNth10Q9EZek4wCUbT/s1600/IMAG0297.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIy_NDhO_IFKWUMIz55XDrmWR7KpvC3gSibWm6p_KGEGDzKurUZyEv3YhMPYALIdL7vnPOajkBCLFS9VcETiOQZ-VJ-jmel0Krk2lVcvqfxyivuPOuAfClmB4HgrYNth10Q9EZek4wCUbT/s400/IMAG0297.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5653387787437461154" /></a><br /><br />This is how the whole setup looks like once connected, the big chip is the AVR .<br /><br />I can write programs in the RAM in two ways:<br /><br />1) Connecting the AVR to my computer through a serial port and use a little loader to upload apps. <br />2) Write the app I want to upload in the AVR's flash and have it write it to the RAM when the Game Boy is turned on.<br /><br />So, bottomline :-) It worked for small apps < 16Kb but it didn't work for bigger apps, so I think this post will have a second part someday, stay tuned!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com1tag:blogger.com,1999:blog-6185874952918981686.post-76067568041468470302010-10-12T08:42:00.000-07:002010-10-14T02:55:06.075-07:00How to get support for the Arduino oscilloscope (and Parallax),We now have a forum, please ask your questions there!<br /><br />http://groups.google.com/group/xoscillo<br /><br />Thanks!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com2tag:blogger.com,1999:blog-6185874952918981686.post-44559850346111306732010-09-29T10:47:00.000-07:002010-10-14T03:00:10.293-07:00Arduino oscilloscope (and Parallax)I wrote some software so you can use your computer as an oscilloscope.<br /><br />In the following screen shot you can see the software acquiring data from an arduino and also from a Parallax USB oscilloscope simultaneously.<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQs2z-3KIO7TNUmRvbzM87XSbplrJMkdpIm9_N4ynkPyGyaj2VCxTQnM_Thyh7NZ83Gxvha6vLh1gisN7rtv1ajZqJ_gVtmLAbll9xnS7fL2tnMnruF_aOs2c1duk-N5uT4oNnjdSHXwrW/s1600/arduino-parallax.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 250px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQs2z-3KIO7TNUmRvbzM87XSbplrJMkdpIm9_N4ynkPyGyaj2VCxTQnM_Thyh7NZ83Gxvha6vLh1gisN7rtv1ajZqJ_gVtmLAbll9xnS7fL2tnMnruF_aOs2c1duk-N5uT4oNnjdSHXwrW/s400/arduino-parallax.png" alt="" id="BLOGGER_PHOTO_ID_5522403072803694354" border="0" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifvS44rA_oKknow1gMTtwNieJYRb33NQwI5tA1aUhw2fJMEJDysYBYuKkk4Gr00F32r6OpWjxc2pCHrfGVdhyphenhyphenDOfPpefI-ZjDK6uMY_Yeyijiy2PoL6Ok8gFoJNiE8zoi1RUXmLrw7Jezf/s1600/arduino-parallax.png"><br /></a><br />For more info, more screen shots and source code go to:<br /><br /><a href="https://code.google.com/p/xoscillo/">https://code.google.com/p/xoscillo/</a><br /><br />We have a wiki with the instructions and a forum, please use them! ;-)Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com9tag:blogger.com,1999:blog-6185874952918981686.post-72306552227450083562010-09-15T05:25:00.001-07:002010-09-16T03:50:38.147-07:00DIY Laser projectorSo yes! Hello!!! This time I built a laser projector, it was built using a toy laser pointer, a pillbox, a cooler fan and an arduino microcontroller.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0rTjoV971jkMv39TMoPO4O_S44FEQqrD8Pqd2EiQQr8HaCR3dIc0tTAHfm137in0qAvl1SyF3WMgnZtZ3FMRnMPT4A9Eo7qvHLEhl0x4gzsRbioO8-glzonsP5aM1W1uF6PQoo1MA5nCO/s1600/IMG_1984.JPG"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0rTjoV971jkMv39TMoPO4O_S44FEQqrD8Pqd2EiQQr8HaCR3dIc0tTAHfm137in0qAvl1SyF3WMgnZtZ3FMRnMPT4A9Eo7qvHLEhl0x4gzsRbioO8-glzonsP5aM1W1uF6PQoo1MA5nCO/s400/IMG_1984.JPG" alt="" id="BLOGGER_PHOTO_ID_5517116154870906002" border="0" /></a><br /><br />Check out this video if you want to see it in motion (note that its a bit dark, but towards the end I turn on the lights)<br /><br /><div style="text-align: center;"><object style="background-image: url("http://i1.ytimg.com/vi/03hpykIyNmA/hqdefault.jpg");" height="344" width="425"><param name="movie" value="http://www.youtube.com/v/03hpykIyNmA?fs=1&hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/03hpykIyNmA?fs=1&hl=en_US" allowscriptaccess="never" allowfullscreen="true" wmode="transparent" type="application/x-shockwave-flash" height="344" width="425"></embed></object><br /></div><br /><span style="font-weight: bold;"><br />Here is how it works!</span><br /><br />In the picture below you can see the whole setup, the heptagon is a pillbox, its sitting on top of a cooling fan so it spins very quickly. Each side of the pillbox has a mirror that reflects the laser beam onto the screen.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpjyHsj3Foqm-RCfYyFXwyfX8v8zGrVQUQuxopi_tlQ6ftL1WaMyISY9ZgIrxyGV0bL2mGtS5jOF7OBn1UtRNcZzOA6atk8mRiMB36UKYVqwwoai47g-SkTQHsUDbexul407IUUtzgBXc5/s1600/IMG_1939.JPG"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpjyHsj3Foqm-RCfYyFXwyfX8v8zGrVQUQuxopi_tlQ6ftL1WaMyISY9ZgIrxyGV0bL2mGtS5jOF7OBn1UtRNcZzOA6atk8mRiMB36UKYVqwwoai47g-SkTQHsUDbexul407IUUtzgBXc5/s400/IMG_1939.JPG" alt="" id="BLOGGER_PHOTO_ID_5517117824750414530" border="0" /></a><br /><br />Because the mirrors are moving the reflected laser dot sweeps the screen from left to right, because it does it very quickly your eyes actually see an horizontal solid line, in this case you see 7 lines one on top of the other because the each mirror is at an angle.<br /><br />So I would get something like this:<br /><span style="font-weight: bold;"><pre><br />-------------------------------------------------<br />-------------------------------------------------<br />-------------------------------------------------<br />-------------------------------------------------<br />-------------------------------------------------<br />-------------------------------------------------<br />-------------------------------------------------<br /></pre></span><br />if I turn off the laser at the right time, I could get to display something like this<br /><pre><br />-- -- -------- -- -- ----- --<br />-- -- -- -- -- -- -- --<br />-- -- -- -- -- -- -- --<br />-------- -------- -- -- -- -- --<br />-- -- -- -- -- -- -- --<br />-- -- -- -- -- -- --<br />-- -- -------- ------- -------- ----- --<br /></pre><br /><br />Then with a little bit of software magic you can get the text to scroll, wave, and so on.<br /><br /><span style="font-weight: bold;"> We are not there yet!</span><br /><br />The spinning speed of the fan is very critical, any slowdown will cause the image to wobble, that is why I put this fins on the pillbox, when they spin they pass thought an optical sensor (pretty much like the one elevators have to keep its doors open when people leave or enter the elevator) A micro controller can use this data to compute the fan speed and adjust the laser blinking to the image looks correct.<br /><br /><span style="font-weight: bold;">Tricky part!</span> (warning quite geeky stuff coming up!)<br /><br />So how does the micro controller know when is the first mirror coming? The fins, because I glued them myself by hand, are not really equally spaced, some are closer that the others, the micro controller notices this and uses this info to tell which one is the first mirror... for example the two fins before the first mirror are a bit closer than the others.<br /><br />That's all, I hope you enjoyed!<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuPbotLKNSvapCeWqi-3S1KJ5cPAYZY3QmibDlPu5pM45QDezWCXTZ49UGx6u0YJNmuD-PWaLcsxZzwUu-JTKxSLFhlj2AIkdsfFfbhmOwIsX58EIJwXS523nHczpvpJyDj13Kvvuv6Jxd/s1600/IMG_1979.JPG"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuPbotLKNSvapCeWqi-3S1KJ5cPAYZY3QmibDlPu5pM45QDezWCXTZ49UGx6u0YJNmuD-PWaLcsxZzwUu-JTKxSLFhlj2AIkdsfFfbhmOwIsX58EIJwXS523nHczpvpJyDj13Kvvuv6Jxd/s400/IMG_1979.JPG" alt="" id="BLOGGER_PHOTO_ID_5517127001543511906" border="0" /></a><br /><span style="font-weight: bold;">Other Laser projectors:</span><br /><br /><a href="http://heim.ifi.uio.no/haakoh/avr/">http://heim.ifi.uio.no/haakoh/avr/</a>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com126tag:blogger.com,1999:blog-6185874952918981686.post-78856579951934670932009-09-13T10:11:00.000-07:002009-10-30T07:41:08.666-07:00poor's man CNC hot wire cutter - Updated!<span style=""><br /> This time I built a computer controlled device that will allow you to cut out shapes from styrofoam boards with great precision.<br /><br /> To make it more fun I tried to build the whole thing by re-purposing scrap parts I found here and there, so I used a couple of scanners, a hanger and a hot wire. The scanners I found them on the trash (officially I will deny that I pick stuff from the trash), the hanger I got it from my cleaning service and the hot wire was 3 euros.<br /><br /> This is the way it works, draw a shape using your favourite drawing software or download one from the internet, just make sure the file is a <a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a>, because that is what my system understands.<br /><br /> I found myself this nice eagle, which is quite a complex shape as you can see: <br /></span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.blogger.com/%20http://www.clker.com/cliparts/f/7/9/a/11949848182045168189eagle_01.svg.thumb.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 83px; height: 100px;" src="http://www.clker.com/cliparts/f/7/9/a/11949848182045168189eagle_01.svg.thumb.png" alt="" border="0" /></a>And this what you get:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNRneRIwoA1P18_fBnDewB0Bnf_BdC2zo5C3QVwK3rFAGfIDbaBFFoeXiCNrkR4xaslxICZkmhgXDhw41exeS9lfC9l0jKy-8q-HDu2ZRUx7jckHE43pWNxMoR9CrZ-DHAab-kHBe-qIbj/s1600-h/IMG_1456.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNRneRIwoA1P18_fBnDewB0Bnf_BdC2zo5C3QVwK3rFAGfIDbaBFFoeXiCNrkR4xaslxICZkmhgXDhw41exeS9lfC9l0jKy-8q-HDu2ZRUx7jckHE43pWNxMoR9CrZ-DHAab-kHBe-qIbj/s400/IMG_1456.JPG" alt="" id="BLOGGER_PHOTO_ID_5381001162119388498" border="0" /></a><br /><br />Here is the promised video so you can see the system in action... <br /><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/y1G15yUXb04&hl=en&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/y1G15yUXb04&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br /><br /><br /><a href="http://www.flickr.com/photos/raul_aguaviva/sets/72157622617789586/">Here are some pictures showing details of the CNC</a>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com27tag:blogger.com,1999:blog-6185874952918981686.post-48876116671761950472009-06-05T10:50:00.000-07:002009-06-05T10:52:19.279-07:00A NintendoDS uses an optical mouse as a camera<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/TOlQrVFjNJs&hl=en&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/TOlQrVFjNJs&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com9tag:blogger.com,1999:blog-6185874952918981686.post-62967700379902325342009-05-30T06:55:00.000-07:002009-05-30T07:15:35.640-07:00Hacking a pager (part 1)I bought this weekend a pager for 2 euros and decided to plug my scope on it to see what could I find out. The case mentions 147.250MHz, and "RTT/SMF/X205", unfortunately this didn't help much!<br /><br />I plug my scope on the digital output of the receiver and I noticed a burst of serial data every 1 second exactly.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLkZO_rIAniI6Y1Kqfq4Ax9oaBWYJ3Fi1IAAnp4qJ1RoDuQZePel9ZX4YdYMSKRmoAyLUz_cXUODST9h6neBVJ5ynKB4SRbmffms0PXt4bccl4kw4KBbf22gsXyWTSmq8BUVBojumvwTQe/s1600-h/oscillo4.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 97px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLkZO_rIAniI6Y1Kqfq4Ax9oaBWYJ3Fi1IAAnp4qJ1RoDuQZePel9ZX4YdYMSKRmoAyLUz_cXUODST9h6neBVJ5ynKB4SRbmffms0PXt4bccl4kw4KBbf22gsXyWTSmq8BUVBojumvwTQe/s400/oscillo4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341615976333664786" /></a><br /><br />I zoomed in to see how this bursts look like and this is what I got:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVodfkn8sgHdklb4snmgX-GSKy-5YfwDyaikztzx2RF489AD471mhdCAX0rv7n8ADy9luBJ1Xnp0sOEFDZ4aMRoRpDNChDodYACXvLo5abG2oeKYy-LqcFrj7MV_i5Xqu27rbZChlE65wv/s1600-h/oscillo1.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 294px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVodfkn8sgHdklb4snmgX-GSKy-5YfwDyaikztzx2RF489AD471mhdCAX0rv7n8ADy9luBJ1Xnp0sOEFDZ4aMRoRpDNChDodYACXvLo5abG2oeKYy-LqcFrj7MV_i5Xqu27rbZChlE65wv/s400/oscillo1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341615965126147234" /></a><br /><br /> BTW the blue channel is hooked to a pin that goes low every time there is serial data coming in the red channel.<br /><br /> The next think I noted, is that once in a while I get loooong bursts of serial data that last for 4 seconds<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsT0iLeopvMudEUZEt28eFrJStASv_yz1lw8KdsrM2I_Bb6mC3mdi0b351EmRA8FeLZCljJEyH3owsLzMSnltPLylQPoICnYxjWmaVHO9ugpCdO3Rkyt6J8r7e4QBG8QxycQ45dVXFZSDC/s1600-h/oscillo3.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 107px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsT0iLeopvMudEUZEt28eFrJStASv_yz1lw8KdsrM2I_Bb6mC3mdi0b351EmRA8FeLZCljJEyH3owsLzMSnltPLylQPoICnYxjWmaVHO9ugpCdO3Rkyt6J8r7e4QBG8QxycQ45dVXFZSDC/s400/oscillo3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5341615970014075650" /></a><br /><br />Any idea what protocol this could be? It doesn't look like FLEX or POGSAC...<br /><br />Thanks everyone for reading, any info is welcome!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com9tag:blogger.com,1999:blog-6185874952918981686.post-4074237617610031692009-03-31T09:56:00.000-07:002009-03-31T11:38:53.262-07:00Logging temperatureDisplaying static pictures on an LCD is quite cool (see my previous post) but it doesn't get you very far, does it? <br /> I always wanted to build my own temperature logger and graph it in a display, so it was now or never! I had a couple of I2C temperature sensors lying around and also a serial EEPROM, so I hooked them all together, and voila voila!!<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwtnuNiS2NR-Lq08InabOcdY9yDXI3A5vtaOcSeJyIwbfJa3gPkmfhp-NIObeHTzq3yl4tomksZ07fm56NtHebuupwJl6dGmr1VBqYH15UQ1_uoK10g0l6OYgd2KAUJ9nBbLTTyJM-KXeG/s1600-h/temp-logger.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwtnuNiS2NR-Lq08InabOcdY9yDXI3A5vtaOcSeJyIwbfJa3gPkmfhp-NIObeHTzq3yl4tomksZ07fm56NtHebuupwJl6dGmr1VBqYH15UQ1_uoK10g0l6OYgd2KAUJ9nBbLTTyJM-KXeG/s400/temp-logger.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5319407160240874610" /></a><br /><br />Time for details now! Sorted from fun to less fun :-)<br /><br />- The data scrolls one pixel every 5 minutes, the LCD is 128 pixels wide I can display the temperature for the last 10.6 hours. <br /><br />- The flat part of the graph is during the night, as you can see the thermostat is doing a great job at keeping a constant temperature! <br /><br />- The non-flat part is during the day the sun enters through the windows and heats up the place. There is a small spike and that is because for while the sun hits directly the sensor.<br /><br />- For the clock, I used the fact that I can drive one of the AVR's timers using an external oscillator, I used a 32.768MHz crystal this number is exactly 128*256, so you just have to set the timer's prescaler to 128 and you'll get a 8bit timer overflowing once a second. Se the timer to generate an interrupt at that point and that's it. Look at the Atmel's Butterfly source code for reference.<br /><br />- Drawing the line was quite tricky, because the LCDs' framebuffer is not linear at all and also because I wanted to write up to 8 pixels with the same memory access. It was tricky but I made it, I'll probably post the code in another post.<br /><br />- The rest is simple stuff, the temperature sensor is a LM75A, and the serial EEPROM is a 128Kb one.. both of them are controlled using and I2C bus, so piece of cake!<br /><br />And now the full monty:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJE2fOME6I5jO-JbU0DBliqTIUQfRn_mT8M00CjAUIW19uGMrDxnc_5Rr6s4qQZVT1IWfj-_BrJjjgGjJDJF9PrDvXd3h0zjh0ZfDITc89lbajuQ4Bbam4Oa_nwIhwfpXDJtH9CTBvtAEE/s1600-h/fullmonty_logger.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJE2fOME6I5jO-JbU0DBliqTIUQfRn_mT8M00CjAUIW19uGMrDxnc_5Rr6s4qQZVT1IWfj-_BrJjjgGjJDJF9PrDvXd3h0zjh0ZfDITc89lbajuQ4Bbam4Oa_nwIhwfpXDJtH9CTBvtAEE/s400/fullmonty_logger.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5319423025352779026" /></a><br /><br />More details on demand, Thanks for reading!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com1tag:blogger.com,1999:blog-6185874952918981686.post-89912452145834454622009-03-22T11:34:00.000-07:002009-03-23T07:29:07.311-07:00GIMP Plugin to export fonts and bitmaps for ks0108 LCDsI wanted to display some cool pictures in my ks0108, GIMP was perfect because it allows me to edit pictures and convert them into 1bpp pictures, the only part that was missing was to have a way to export the picture in a format that I could easily embed in my firmwares and that I could send quickly to the LCD. <br /><br /> So voila voila! here is the missing part, a very cool plug-in that does exactly that, this plug-in saves the data into a C source code header file, and arranges the data in a way that can be uploaded to the LCD quickly and with minimal code.<br /><br /> Details about installing it, and loading the data are embedded in the python plug-in file that you can get <a href="http://registry.gimp.org/node/14964">here</a>.<br /><br /> And now the pictures!<br /><br />The artwork for this one was ripped form <a href="http://en.wikipedia.org/wiki/Knight_Lore">Knight Lore</a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRgpddtaY8fC0r1Ibhee1DMIbng9TZrjzD0ES80Zyv1lbWhTe_-bvhjBOVvyvmOmXGkJai0DXbe5mk2XxC_ghR8s76yqNw4VCev6tJkaVivKXE2rLVwI3NluXXxYrLXrPIWL7Gd7QLkBYv/s1600-h/ks0108_lore.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRgpddtaY8fC0r1Ibhee1DMIbng9TZrjzD0ES80Zyv1lbWhTe_-bvhjBOVvyvmOmXGkJai0DXbe5mk2XxC_ghR8s76yqNw4VCev6tJkaVivKXE2rLVwI3NluXXxYrLXrPIWL7Gd7QLkBYv/s400/ks0108_lore.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5316084041182128546" /></a><br /><br /> This picture was taken for the 8bit game <a href="http://www.worldofspectrum.org/infoseekid.cgi?id=0000047">The Abbey of Crime</a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrTIUPMzcmzxRw4lCX9hhEjU4D-MqySZW8L5t3LPqbAJ5LQ7GQA0inFxji_7WwuBNKGP8g7PKxxD8lBXTcKhyphenhyphen68cufoGuEV312Hpj6lCzuJef43MVc_Tioohu6z6FaHHPedRkkMASHQ1Li/s1600-h/abadia.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrTIUPMzcmzxRw4lCX9hhEjU4D-MqySZW8L5t3LPqbAJ5LQ7GQA0inFxji_7WwuBNKGP8g7PKxxD8lBXTcKhyphenhyphen68cufoGuEV312Hpj6lCzuJef43MVc_Tioohu6z6FaHHPedRkkMASHQ1Li/s400/abadia.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5316367112949312546" /></a><br /><br /> And this is the whole shebang, just ripped the KONAMI logo from a MSX game<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC_v3oz7L6sadTLyzuzYq0BlaXL_WQ6WOeAkXty7fOrn8TribMyrsGdXYEJf2lEK8xWyNLr_VKxnxnfmNXifw5Ap8qTYSATz2Y0wzPw3bnLTwIgACVjFWjdvUcOjxgRJ6RK5zY-njW_UBv/s1600-h/whole_setup_konami.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC_v3oz7L6sadTLyzuzYq0BlaXL_WQ6WOeAkXty7fOrn8TribMyrsGdXYEJf2lEK8xWyNLr_VKxnxnfmNXifw5Ap8qTYSATz2Y0wzPw3bnLTwIgACVjFWjdvUcOjxgRJ6RK5zY-njW_UBv/s400/whole_setup_konami.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5316384967521852786" /></a><br /><br />You can also use your bitmap as a font if you arrange letters in the following way :<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG6MzN1_taTibJYARHPuUetw0sZbgXH96oI0jVp_W16LHVJGsDBELDVmYYuSocEUvsJD5SXFHVwfYF38LhHPOryHBRmlN3_y_9f0uiaf0jdU_Qf0Djz_YFzUAJSlMOL7bRX8oYge68vYpM/s1600-h/cool_font.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG6MzN1_taTibJYARHPuUetw0sZbgXH96oI0jVp_W16LHVJGsDBELDVmYYuSocEUvsJD5SXFHVwfYF38LhHPOryHBRmlN3_y_9f0uiaf0jdU_Qf0Djz_YFzUAJSlMOL7bRX8oYge68vYpM/s400/cool_font.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5316389675149130658" /></a><br /><br /><br /> Hopefully with this script we'll start seeing new cool bitmaps/fonts in projects, besides from the usual suspects we are used to see :-)<br /><br /> If you use it you are welcome to drop me a line, that will probably encourage me to write more free software!<br /><br /> The next step is to export the bitmap in binary format so I can store it in an serial EPROM (rather than using the chips flash) , but I guess thats all for now, enjoy!<br /><br />Notes:<br /> I used M-A Loyer's <a href="http://www.weirdfox.com/assets/files/nds-engine/nds_export_py.txt">exporter for NDS</a> as a reference for mine, thanks!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com3tag:blogger.com,1999:blog-6185874952918981686.post-51365523723456330592009-03-08T12:01:00.000-07:002009-03-08T16:09:35.434-07:00weekend project: reading 27256 epromsOne of my favourite hobbies is to open electronic devices to see what is inside, to hack it or to scavenge its circuits. For that I usually buy quite old devices since the new ones all use SMD and there is not much you can do with them. <br /><br /> Luckily in the city where I live there is a secondhand/flea market where you can buy all kind of stuff and I found a cool device (see the picture below) and when I opened it I discovered a bunch of <a href="http://www.futurlec.com/Memory/27256-250.shtml">27256</a> EPROM's inside.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4cf8jZaMk3rotXhHzV_MVTcMAFDVh7JOvY9DLVkxnY8WJ4XDvrXsIEA3BYhzKGax53e3ATkAF_123-9v8OF5YatKjS2qBLdzF0nt8djIQmPbO3ksNIRL5xB9ei-Z1HKYgOg_sdazBre3l/s1600-h/IMG_1380.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4cf8jZaMk3rotXhHzV_MVTcMAFDVh7JOvY9DLVkxnY8WJ4XDvrXsIEA3BYhzKGax53e3ATkAF_123-9v8OF5YatKjS2qBLdzF0nt8djIQmPbO3ksNIRL5xB9ei-Z1HKYgOg_sdazBre3l/s400/IMG_1380.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5310906290157000226" /></a><br /> <br /> These EPROM's have a 15bit's address bus and a 8bit data bus. As the microcontroller I used an Atmega128 connected to my computer thought a serial port. The microcontroller sets the address in the bus using a couple of 74HC595 (8-bit serial-in, serial or parallel-out shift register), that way I only need 3 GPIO's to set the address I want to read from, for the data I just use the whole (ouch!) PORTA of the microcontroler. <br /><br /> It all worked pretty straight forward, the only problem I had is that by mistake I wired the data bus in the reverse order (so D0 was connected to D7, D1 to D6 and so on) but once I figured that out I dumped the EPROM again and got a great satisfacton when I read the strings stored in the EPROM :-))<br /><br />Ok, so here come the pictures and a bit of the EPROM DUMP<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFeBv1j_s8u3tXflsOqkvPhD2X_jSn7ViKOEyiEPXY5c34W0wbOGkiIzowm_dtA_vni3plinSo6dcGum0xFsExi4vQ-Jdm9PEgQvZBxRwJBlmAS77MClHg23Yik1JHst242FgsR4Z58ZZY/s1600-h/IMG_1378.JPG"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFeBv1j_s8u3tXflsOqkvPhD2X_jSn7ViKOEyiEPXY5c34W0wbOGkiIzowm_dtA_vni3plinSo6dcGum0xFsExi4vQ-Jdm9PEgQvZBxRwJBlmAS77MClHg23Yik1JHst242FgsR4Z58ZZY/s400/IMG_1378.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5310903106259405634" /></a><br /><br /><font size="1"><br /><pre><br />0000 02 05 48 02 56 09 FF FF FF FF FF 02 07 83 FF FF ..H.V...........</br><br />0010 FF FF FF 02 6C 51 FF FF FF FF FF 32 FF FF FF FF ....lQ.....2....</br><br />0020 FF FF FF 02 45 18 FF FF FF FF FF 32 FF FF FF FF ....E......2....</br><br />0030 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 0123456789ABCDEF</br><br />0040 46 41 54 41 4C 20 43 52 4F 4D 20 45 52 52 4F 52 FATAL CROM ERROR</br><br />0050 46 41 54 41 4C 20 49 52 41 4D 20 45 52 52 4F 52 FATAL IRAM ERROR</br><br />0060 58 52 41 4D 20 45 52 52 20 7E 20 7E 5F 5F 5F 5F XRAM ERR ~ ~____</br><br />0070 46 49 52 4D 57 41 52 45 20 45 52 52 4F 52 20 20 FIRMWARE ERROR </br><br />0080 53 59 4E 54 41 58 20 46 49 4C 45 20 45 52 52 20 SYNTAX FILE ERR </br><br />0090 43 4F 4E 46 49 47 20 46 49 4C 45 20 45 52 52 20 CONFIG FILE ERR </br><br />00A0 54 52 41 4E 53 2E 20 46 49 4C 45 20 46 55 4C 4C TRANS. FILE FULL</br><br />00B0 54 52 41 4E 53 2E 20 50 41 43 4B 20 45 52 52 20 TRANS. PACK ERR </br><br />00C0 54 52 41 4E 53 2E 20 42 59 54 45 20 5A 45 52 4F TRANS. BYTE ZERO</br><br />00D0 2A 20 42 41 54 54 45 52 59 20 4C 4F 57 20 2A 20 * BATTERY LOW * </br><br />00E0 2A 2A 20 42 59 50 41 53 53 20 4F 4E 20 2A 2A 20 ** BYPASS ON ** </br><br />00F0 20 44 41 54 45 29 20 44 44 2D 4D 4D 4D 2D 59 59 DATE) DD-MMM-YY</br><br />0100 20 54 49 4D 45 29 20 48 48 3A 4D 4D 20 20 58 4D TIME) HH:MM XM</br><br /> [....]</br><br /></pre><br /></font>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com0tag:blogger.com,1999:blog-6185874952918981686.post-34919768578072564812009-02-18T12:57:00.000-08:002009-02-18T14:45:40.035-08:00Making a SO8 IC's breakout board out a stripboardHi! I just came across a 1Mbit I2C eprom but neither I had a breakout board nor I wanted to buy one. Also I really like solving problems with the stuff I have at home, so I decided to try using a stripboard, a little bit of inconscience and another bit of selfconfidence. And I made it!! <br /><br />The images explain it all, <br /><br />This is the picture of the stripboard with some of the strips cut, also see the red outline that shows where the IC will go:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBNyyMOewFL5_UHoR2-F6dy-44moaGhYeNqdsrN5Hj81X5Chef5LaGpaCvmIqygiucZhulawDGcQ7Xccm9qeOm1sVu_XIlkH6gpK2ThhUw_TYdKRHZCDtHoD28ZMWiMXoCuPqBV9Zai7Lc/s1600-h/second.jpg"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBNyyMOewFL5_UHoR2-F6dy-44moaGhYeNqdsrN5Hj81X5Chef5LaGpaCvmIqygiucZhulawDGcQ7Xccm9qeOm1sVu_XIlkH6gpK2ThhUw_TYdKRHZCDtHoD28ZMWiMXoCuPqBV9Zai7Lc/s400/second.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5304264981758715058" /></a><br /><br />A IC's close up from the top once welded, I used a lead-free welding alloy, that is why the welds look so ugly, anyway health goes first:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtvLMQk9s0ve_sHXEArHo5NDlqHbPFO55MSFWESGrc1lvPu8zT0wwLKz923mRJLzV9VHCfYEiLWLHKcgW-oohsBZIgUpjdC4SVwcmWg-hazjtTajXFqGITNQtGmtQM_2mPFwOZj5sFVwpz/s1600-h/top.jpg"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtvLMQk9s0ve_sHXEArHo5NDlqHbPFO55MSFWESGrc1lvPu8zT0wwLKz923mRJLzV9VHCfYEiLWLHKcgW-oohsBZIgUpjdC4SVwcmWg-hazjtTajXFqGITNQtGmtQM_2mPFwOZj5sFVwpz/s400/top.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5304263962276477554" /></a><br /><br /><br />And voila! Ready to use in my protoboard:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvGZcItxvU7NqgylBHNLGkAyt_6ZhGt1LsamNwpP1uvcq55sqi4_zpOFiXPdeCIsdbeyi8ljkZhP6FfacNiRr0VJDXI_Bq8lu62xMFoZxEkBWvTctKqFCpUXE4wNahI1b8O14Y28_eXb9N/s1600-h/third.jpg"><img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvGZcItxvU7NqgylBHNLGkAyt_6ZhGt1LsamNwpP1uvcq55sqi4_zpOFiXPdeCIsdbeyi8ljkZhP6FfacNiRr0VJDXI_Bq8lu62xMFoZxEkBWvTctKqFCpUXE4wNahI1b8O14Y28_eXb9N/s400/third.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5304263959999277698" /></a><br /><br />No I just have to figure out what to store in it :-)<br /><br />Enjoy!Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com6tag:blogger.com,1999:blog-6185874952918981686.post-77348612117514917762008-10-29T17:43:00.000-07:002009-02-18T14:35:20.972-08:00Temperatures in my appartmentJust got an I2C temperature sensor and I decided to connect it to my NintendoDS to measure the temperature for two whole days.<br /><br />The two spikes on the left is the sun entering through two different windows and hitting the sensor directly. The other two spikes on the right is exactly the same thing but for the second day.<br /><br /><img src="http://spreadsheets.google.com/pub?key=pSlC9D-5jLL2mOV6tW6yqXg&oid=3&output=image" /><br /><br />Thats it.Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com0tag:blogger.com,1999:blog-6185874952918981686.post-19199723480703223222008-10-14T13:20:00.000-07:002013-02-27T14:33:19.261-08:00I2C on an AVR using bit bangingAs a exercise I tried to talk to a I2C temperature sensor using bit banging, it was not as easy as I thought so I decided to post the code in case anyone needs to see the solution, if you happen to use my code drop me a line since that will encourage me to post more code :-)<br />
<br />
<pre class="prettyprint">// Port for the I2C
#define I2C_DDR DDRD
#define I2C_PIN PIND
#define I2C_PORT PORTD
// Pins to be used in the bit banging
#define I2C_CLK 0
#define I2C_DAT 1
#define I2C_DATA_HI()\
I2C_DDR &= ~ (1 << I2C_DAT);\
I2C_PORT |= (1 << I2C_DAT);
#define I2C_DATA_LO()\
I2C_DDR |= (1 << I2C_DAT);\
I2C_PORT &= ~ (1 << I2C_DAT);
#define I2C_CLOCK_HI()\
I2C_DDR &= ~ (1 << I2C_CLK);\
I2C_PORT |= (1 << I2C_CLK);
#define I2C_CLOCK_LO()\
I2C_DDR |= (1 << I2C_CLK);\
I2C_PORT &= ~ (1 << I2C_CLK);
void I2C_WriteBit(unsigned char c)
{
if (c > 0)
{
I2C_DATA_HI();
}
else
{
I2C_DATA_LO();
}
I2C_CLOCK_HI();
delay(1);
I2C_CLOCK_LO();
delay(1);
if (c > 0)
{
I2C_DATA_LO();
}
delay(1);
}
unsigned char I2C_ReadBit()
{
I2C_DATA_HI();
I2C_CLOCK_HI();
delay(1);
unsigned char c = I2C_PIN;
I2C_CLOCK_LO();
delay(1);
return (c >> I2C_DAT) & 1;
}
// Inits bitbanging port, must be called before using the functions below
//
void I2C_Init()
{
I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
I2C_CLOCK_HI();
I2C_DATA_HI();
delay(1);
}
// Send a START Condition
//
void I2C_Start()
{
// set both to high at the same time
I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
delay(1);
I2C_DATA_LO();
delay(1);
I2C_CLOCK_LO();
delay(1);
}
// Send a STOP Condition
//
void I2C_Stop()
{
I2C_CLOCK_HI();
delay(1);
I2C_DATA_HI();
delay(1);
}
// write a byte to the I2C slave device
//
unsigned char I2C_Write(unsigned char c)
{
for (char i = 0; i < 8; i++)
{
I2C_WriteBit(c & 128);
c <<= 1;
}
//return I2C_ReadBit();
return 0;
}
// read a byte from the I2C slave device
//
unsigned char I2C_Read(unsigned char ack)
{
unsigned char res = 0;
for (char i = 0; i < 8; i++)
{
res <<= 1;
res |= I2C_ReadBit();
}
if (ack > 0)
{
I2C_WriteBit(0);
}
else
{
I2C_WriteBit(1);
}
delay(1);
return res;
}</pre>Raulhttp://www.blogger.com/profile/05112542436303049493noreply@blogger.com20