Saturday, May 21, 2016

ADC IIR LPF SPI TFT LCD GUI - Part 1

I have a project in which I need to read a signal, do some processing and display the results using a bar graph. After some fiddling with an Arduino UNO and researching the AVR microcontrollers they use, I settled on a two-MCU architecture. I use an Arduino Nano to acquire and process the data and an Arduino Mega to display the results and interface with the user. How many acronyms can be squeeze into a title?

ADC - analog-to-digital converter
IIR - infinite impulse response
LPF - low pass filter
SPI - serial peripheral interface
TFT - thin film transistor
LCD - liquid crystal display
GUI - graphical user interface

My first problem: how to get two Arduino’s to chat with each other. My work is based upon (copied from) a thorough and accurate forum post. The motivation to use SPI came from wanting to learn more about it. In researching the TVout library, I found someone generated an NTSC signal with the hardware based SPI master signal.  Given my current fascination with resurrecting my Atari days, I had an idea of trying to recreate a simplified ANTIC-like system on an Arduino in black and white. SPI seems the way to go there. But, back to my project.



The system here uses a Nano to read an analog voltage and apply a low pass filter. The Mega polls the Nano for the LPF output over SPI and displays the value on a bar graph. I offloaded the ADC work to the Nano thinking I would eventually use an interrupt-driven ADC to get a constant sampling rate. Because the TFT polls various analog channels to read the touchscreen, it seemed best to just off-load the other ADC work to a different microcontroller. The TFT fits on the Mega and leaves the header with the SPI interface unobstructed.

The SPI connections on the Nano are located on the ICSP header or pins D11-D13 and Slave Select is D10. The connections on the Mega are on the bottom header pins D50-D53. Connections are one-to-one. That is MISO:MISO, MOSI:MOSI, SCK:SCK, and SS:SS. The Master-In-Slave-Out MISO signal transfers data from the Nano to the Mega because the Nano is set up as SPI Slave and the Mega as Master. Vice-versa for MOSI. Serial Clock (SCK) sends a 2 MHz clock from the Mega to the Nano. And Slave Select (SS) signals the Nano to listen on SCK & MOSI for data and to send data on MISO synchronized to SCK. I use 2 Mbps because single-ended communications over long wires can’t go all that fast.

To low-pass filter the data, I use an exponential moving average filter implemented as an infinite impulse response (IIR) digital filter. This is very efficient because it requires only a weighted average of the current sample with the previous output. For a C++ implementation, I followed the integer implementation here. I had to add some additional 64-bit integer type casting to the coefficients in the filter equation to get it to operate correctly.. I also changed how the filter coefficient is implemented as a 16-bit unsigned integer (0-65535). The original author designed it to represent floats ranging from 1/65535 to 1 and I changed it to the range 0 to 65535/65536. Just personal preference. You can see the effect of the filter in the video - I adjust the potentiometer abruptly and it takes some time for the bargraph to totally respond.

Master Code

// Jeff Piepmeier - May 2016
//
// Main program adapted from SPI demo
// at http://www.gammon.com.au/spi 
// by Nick Gammon April 2011

//set up TFT display
#include <SPFD5408_Adafruit_GFX.h>
#include <SPFD5408_Adafruit_TFTLCD.h>
#include <SPI.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// variables for bar graph
int newHeight;
int oldHeight = 0;
int heightDiff;

void setup (void)
{
  // Serial.begin (115200);
  // Serial.println ("SPI demo");
  
  // SS = slave select, built in AVR output pin reference 
  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  tft.reset();
  tft.begin(0x9341);
  tft.fillScreen(0x0000); // make the screen black
    
  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  SPI.begin ();

  // Slow down the master a bit
  //SPI.setClockDivider(SPI_CLOCK_DIV4);
  // use 2 Mbps decided by testing. 4 Mbps has too many bit errors over 
  // jumper wires. Single-ended signals are not well suited for high-speed over wires
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));

}  // end of setup

void loop (void)
{
  byte a=0; // variable to store SPI input data from Nano
  
  // get a value from the SPI - we're the master so have to ask for it from slave
  // enable Slave Select
  digitalWrite(SS, LOW);    
  a = SPI.transfer ('a');
  // disable Slave Select
  digitalWrite(SS, HIGH);

  newHeight=(int)(((long)a*319)/256); // hardcode display height of 320 lines
  heightDiff = oldHeight-newHeight; // only draw new part of bar graph for faster display
  if (heightDiff>0) { tft.fillRect(80, newHeight+1, 80, heightDiff+1, 0x0000); }
  else if (heightDiff<0) { tft.fillRect(80, oldHeight-1, 80, -heightDiff+1, 0xFFFF); }
  oldHeight=newHeight; // remember how high bar is
  
  // Serial.println (a, DEC);
}  // end of loop


Slave Code

// Main program is adapted from SPI demo at
// http://www.gammon.com.au/spi
// Written by Nick Gammon
// April 2011
//
// IIR Exponential Moving Average (EMA) Low Pass Filter (LPF)
// adapted from C++ code at
// http://stratifylabs.co/embedded%20design%20tips/2013/10/04/Tips-An-Easy-to-Use-Digital-Filter/

// filter coefficient float-to-uint16 conversion - min 0, max x=1 means 65535/65536=.9999847
#define DSP_EMA_I32_ALPHA(x) ( (uint16_t)(x * 65535) )

volatile byte command = 0;
volatile byte out1 = 0;

void setup (void)
{

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  digitalWrite(MISO, LOW); //ensure is low to start
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);

}  // end of setup

//http://stratifylabs.co/embedded%20design%20tips/2013/10/04/Tips-An-Easy-to-Use-Digital-Filter/
int32_t dsp_ema_i32(int32_t in, int32_t average, uint16_t alpha){
  int64_t tmp0;
  tmp0 = (int64_t)in * (int64_t)(alpha) + (int64_t)average * (int64_t)(65536 - alpha);
  return (int32_t)((tmp0 + 32768) / 65536);
}

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  command = SPDR; // not yet used here
  SPDR = out1; 
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  uint16_t adcReading = 0;
  static int32_t avg1 = 0;
  adcReading=analogRead(0); //10 bit unsigned, shift up to 31 bits for signed long int
  avg1=dsp_ema_i32( (int32_t)adcReading << 21, avg1, DSP_EMA_I32_ALPHA(0.0005));
  out1=byte(avg1 >> 23 ); // shift down to single byte
}  // end of loop




Sunday, March 27, 2016

Easter 3D Print (and Splitting a 3D Model in Half)

Holidays are a good excuse to find something whimsical to 3D print. I found this pair of egg legs over on Thingiverse and chuckled. The legs are pose-able and hold an egg. Wife sketched an Humpty Dumpty on an egg and suggested I shoot the model in the garden. He can stand (above) or sit (below).

When I loaded up the model, I discovered the pieces would be difficult to print. Turns out the original designer is a grad student at MIT Media Lab and has access to a fancy industrial grade fabricator. On hobby printers, 3D objects are easiest to print when they have one flat face to serve as a base. For example, pyramids are easy to print and good for testing a printer setup. Otherwise, when an object has a part that hangs in mid air, the printing software can insert extra material for support. Sometimes though, some objects are just unprintable.

This model has 5 pieces: feet, lower legs, left & right upper legs, and a torso. The feet were easy. The lower legs printed OK with support. I rotated the upper legs 90 degrees and printed them with support. The "egg holding torso" print, however, failed miserably. To solve the problem, I was able to make my own flat face on the object by slicing it in half, printing the two halves, and super-gluing them together.

Surprisingly, there are few solutions for cutting 3D model objects in half to be googled-up. I ended up using Meshmixer, with which I've had varying success in the past. This time, however, it worked perfectly. Import the STL file and select "plane cut" under the "edit" menu. The default plane was oriented exactly along the major axes, splitting the part in half easily.
Print two, glue, build, pose, photograph, write a blog post. Happy Easter.

Sunday, March 20, 2016

GRAVITEN (An Atari Gravitar rip-off in 10 lines of BASIC)

UPDATE April 3, 2016: 2nd Place!


GRAVITEN is my second entry to the 2016 NOMAM 10-liner BASIC game competition. Like NUTS!, this one is in the PUR-120 category. It's inspired by Gravitar's Red Planet 3 stage by Atari. I got the idea last Friday night playing Gravitar on my Atari 2600 10-in-1 joystick game. I had tried playing it as a kid, but found it too hard. Download my version here and run it on the Altirra emulator (800XL). (Direct link to ATR file.) If you play, please post your high-score in the comments!

Pilot your ship around the spiral to the planet's core. Reach the core and advance to the next level. Complete each level quickly to maximize points. But, be careful! Touch the wall and you lose a life.You get 3 lives to start and 1 additional life per level. Even numbered levels have atmospheric drag (indicated by gray background in the text window) and odd are in vacuum (indicated by black background). Gravity increases every two levels, starting at zero. Play through all 8 levels to complete the mission.  Controls: up to thrust, back to flip, left/right to rotate.


I learned a couple new things to write this game. I used Altirra's debug features to borrow the ship bitmap from Asteroids. Altirra can report the ANTIC register values allowing one to find the player-missile pixel graphics in memory. I also learned to use the TurboBasic XL parser tool (tbxl), which is really useful for at least two things: (1) storing binary data in strings using ATASCII characters and (2) optimizing code to squeeze into minimal space.


The Code

0DIMA$(96):A$=" ......................... {a whole bunch of ATASCII} ......................... ":A=.39269908:DIMA(1,15)
1F.B=0TO15:A(0,B)=SIN(A*B):A(1,B)=COS(A*B):N.B:GR.8:GR.5:POKE752,1:SE.0,3,4:SE.2,0,4:C.1:PAI.0,0:C.0:C=580:?"GRAVITEN"
2?"Stand by ";:A=.0174532925:F.B=0TOC STEP9:D=38*B/C*COS(B*A)+45:E=25*B/C*SIN(B*A)+15:F.F=1TO5:CI.D,E,F:N.F:?".";:N.B
3CLS:C.1:PL.0,0:DR.79,0:PL.19,39:DR.79,39:C.2:CI.46,15,1:G=44032:M.ADR(A$),G,80:POKE704,15:POKE54279,G/256:POKE53277,3
4POKE559,46:DO:?:?,"press FIRE to start";:W.STRIG(0):WE.:CLS:H=1e3:I=0:J=3:K=70:L=18:M=8:N=0:O=0:?:?I,J;:W.J:POKE657,22
5?H;" ";:M.G+512,G+513,127:M.M*5+G,G+512+INT(L),5:POKE53248,INT(K):P=Q:Q=STICK(0):R=(Q&4=4)-(Q&8=8):S=(P&2=2)&(Q&2=0)
6T=Q&1=0:M=(M+16+R+8*S)MOD16:IFT:SO.0,250,10,10:N=A(0,M)*.05+N:O=A(1,M)*.05+O:END.:IFI MOD2=0:N=N-.01*N:O=O-.01*O:END.
7N=I DIV2*2e-5*(135-K)+N:O=O-I DIV2*2e-5*(44-L):K=K+N:L=L-O:POKE53278,1:PA.1:U=PEEK(53252):IFU:K=70:L=18:M=8:N=0:O=0
8SO.0,50,U*8-6,15:PA.9:CLS:IFU=1:J=J-1:IFJ=0:?,"TRY AGAIN":END.:END.:IFU=2:H=(I+1)*1e3+H:IFI=7:?,"MISSION COMPLETE!":EX.
9END.:I=I+1:J=J+1:SE.0,I*2+3,4:SE.2,0,4-I MOD2*4:END.:?:?I,J,H;:END.:SO.0,0,0,0:H=H-1:WE.:?,"SCORE:";H:SO.0,0,0,0:LOOP

There are a couple of things worth pointing out in this code: the spiral path generation (in line 2) and the ship dynamics (in lines 6 & 7). The path is carved out of a solid field of color - this allows me to use missile-playfield collision detection to find out when the ship hits the wall. A TurboBASIC XL PAINT command is used to fill the screen. The spiral path is generated using a pair of parametric equations describing the polar coordinate equation r = aΘ. For each point on the curve, five concentric circles are drawn in the background color, which erase the foreground to create the path. A couple of lines are drawn to repair the top and bottom and to enclose the whole payfield in COLOR 1. Finally, a small box is plotted with the CIRCLE command in COLOR 2 for the goal.

The ship dynamics are borrowed from the earliest video games (Spacewar! and much later Asteroids), which based their game play on similar physics. Those two and other games used thrusters, gravity and drag in their game play. In Gravitar, there's gravity located in different places depending upon the scene. Here, the gravity is centered on the core (goal) and approximated so that it weakens as one progresses into the planet. The strength of the gravity is scaled by the level so higher levels become increasingly more difficult. I made it fairly weak because I'm not a very good gamer. In Asteroids, the ship encounters atmospheric drag - maybe it's the dust and debris ablated from the main rocks. I enable drag every other level. It's slightly easier to play with drag - it acts as a damper to over zealous thrust. You can almost point the ship where you want to go and hit the thursters. Without drag, once the ship starts moving in a direction, it doesn't change until a counter acting thrust is applied or gravity is present.

Thanks for reading.

Sunday, February 28, 2016

NUTS! - Atari BASIC 10-Liner Contest 2016 Entry

Update April 3, 2016: 3rd Place!


Climb the trees, jump to gather acorns, but beware the blue jays! Earn points by climbing (press fire) and jumping left and right (move the joystick) to collect acorns, which only fall when you are climbing. The acorns are worth more the higher you climb, but there are more blue jays, too. The game is over when you run into a blue jay. Your high-score is recorded so you can try and beat it the next round. Grab the ATR here and play it on your favorite emulator (I use Altirra).

This is only my second BASIC program in modern times and is my entry to the NOMAM 2016 BASIC 10-Liner Contest. I like the 10-line constraint and find it a fun (for now) challenge to do my own code optimization squeezing it into 10 x120-character lines. For this program, I wrote it up in stages, getting each feature to work. I saved doing the pixel art for near the end. In the middle of development, I tested on the boy. He made me remove a timer:

"Dad, gamers hate timers in a runner, which is what this is." 

So, I removed the countdown timer and added an algorithm to increase difficulty with advancement. (More birds the more you climb.) After I compressed it down with single-character variable names, abbreviated statements, and some hand-optimized coding, I had space left over. I added sound effects in the remaining character count. I was surprised by how much more enjoyable the game play was with sound effects. Read on for the code. Here's a video of the final product. 



Here's the code listing in 10 lines each 120 characters or fewer:
0 DIMS$(76):S$="{...a mess of ATASCII...}":Q=ADR(S$):R=PEEK(106)
1 POKE106,R-8:GR.1:POKE106,R:CLS:POKE54279,R-4:POKE559,46:DP.53256,257:DP.53258,257:POKE53277,3:DP.708,$12C4:P=(R-4)*256
2 W=53248:DP.W,$6868:DP.W+2,$7888:DP.704,$850A:DP.706,$1D85:M.Q+64,DPEEK(560)+7,12:M.57344,(R-8)*256,1024:POKE756,R-8
3 M.Q+56,(R-8)*256+264,8:?#6;"NUTS!","HI:";J:?#6;"SCORE:":F.X=0TO10:?#6;" aaaaaa aaaaaa":N.X:F=1:S=16:H=104:B=1:E=0
4 D=12:G=16:K=0:Z=1:DO:POKE53278,1:A=2*STRIG(0):IFF=0:F=PTRIG(0)-PTRIG(1):END.:IFA=0:-M.P+664,P+666,78:-M.P+792,P+794,78
5 SO.1,0,Z,2:Z=Z=0:K=K+1:S=S-4:IFS<0:S=15:END.:IFB:D=D-2:M.Q+22-B*6+D,P+728-64*B,2:B=B*(D>0):EL.:B=(RND>(1-L))-(RND<L)
6 D=12:L=K/5E3:END.:END.:IFE:G=G-4+A:M.Q+40+G,P+920,4-A:E=G>0:EL.:G=16:E=(2-A)*(RND>.9):END.:-M.P+920,P+924-A,78:IFF=-1
7 IFH=104:F=0:EL.:H=H-8:M.Q,P+589,8:END.:END.:IFF=1:IFH=136:F=0:EL.:H=H+8:M.Q+8,P+589,8:END.:END.:POKEW,H:SO.0,0,0,0
8 X=PEEK(53260):SO.1,0,0,0:IFX&8:SO.0,50,10,15:K=K+K DIV 5:-M.P,P+964,28:ELSE:IFX&6:EXIT:END.:END.:POS.6,1:?#6;K;
9 SO.2,H,10+(F=0),6:PAUSE 0:POKE54277,S:LOOP:IFK>J:J=K:END.:SO.2,0,0,0:G.1

Below is the expanded code with commentary following each group of statements.

DIM S$(76)
S$="...{a bunch of ATASCII}..."
Q=ADR(S$)
Sets up a string full of ATASCII characters containing the pixel graphics for the acorn, squirrel, bluejay, and tree bark. The end contains characters making up part of the display list to enable vertical scrolling. The address of the string is stored in Q, which I use many times copy parts of the string into memory locations.

R=PEEK(106)
1 POKE 106,R-8
GRAPHICS 1
POKE 106,R
CLS 
Sets up the screen and creates blank memory for storing sprites and custom character set. The line #1 is used a jump at the end a game to restart another round.

POKE 54279,R-4: POKE 559,46: DPOKE 53256,257: DPOKE 53258,257: POKE 53277,3: DPOKE 708,$12C4: P=(R-4)*256: W=53248: DPOKE W,$6868: DPOKE W+2,$7888: DPOKE 704,$850A: DPOKE 706,$1D85
Sets up player-missile (sprite) graphics and colors. Turbo BASIC XL's double poke (abbreviated DP.) is great for saving code space when you need to set two adjacent 1-byte registers.

MOVE Q+64,DPEEK(560)+7,12
Modify the display list to make all but the first two rows Graphics 2 mode with vertical scrolling.

MOVE 57344,(R-8)*256,1024: POKE 756,R-8: MOVE Q+56,(R-8)*256+264,8
Copy the default character set into RAM and put a custom character into the "A" location. Point the hardware here.

? #6;"NUTS!","HI:";J: ? #6;"SCORE:": FOR X=0 TO 10: ? #6;" aaaaaa      aaaaaa": NEXT X
Draw the playfield onto the screen. The uppercase letters are printed in green. The lowercase "a" points to my special tree bark character with the brown color.

F=1: S=16: H=104: B=1: E=0: D=12: G=16: K=0: Z=1
Initialize a bunch of state variables, e.g. H is the horizontal position of the squirrel.

DO
Begin the main loop!

POKE 53278,1
Clear the collision register.

A=2*STRIG(0)
IF F=0:F=PTRIG(0)-PTRIG(1):ENDIF
Get joystick input. Only read the left/right direction if the squirrel is not jumping (F=0).

IF A=0
Now begins a large set of actions if the user has the fire button pressed:

-MOVE P+664,P+666,78: -MOVE P+792,P+794,78
These two move commands scroll the blue jays down the screen.

SOUND 1,0,Z,2: Z=Z=0
Play the climbing sound and toggle it on and off with flag Z. This takes advantage of the odd numbered distortion values being no sound.

K=K+1
Increase the score by one for climbing.

S=S-4: IF S<0: S=15: ENDIF
Smooth scroll 1/4 of a character to make it look like the squirrel is going up the tree.

IF B: D=D-2: MOVE Q+22-B*6+D,P+728-64*B,2: B=B*(D>0)
If there's a bird being scrolled onto the tree ... then put two lines of the sprite onto the screen at a time. Turn off B when the whole bird makes it.

ELSE: B=(RND>(1-L))-(RND<L): D=12: L=K/5000
Otherwise test to see if there's a new bird. Compute the likelihood based on the score.

ENDIF: ENDIF
End of the bird conditional (IF B). End of the climbing conditional (IF A=0).

IF E: G=G-4+A: MOVE Q+40+G,P+920,4-A: E=G>0
If there's an acorn entering the screen ... introduce either 2 or 4 lines of the acorn at a time depending upon the climbing state.

ELSE: G=16: E=(2-A)*(RND>0.9)
Otherwise figure out if we need another acorn, but only if the squirrel is climbing. This prevents a player from parking out and collecting acorns with no other challenge.

ENDIF : -MOVE P+920,P+924-A,78
Scroll the acorns down the screen.

IF F=-1
  IF H=104
    F=0
  ELSE
    H=H-8: MOVE Q,P+589,8
  ENDIF
ENDIF
IF F=1
  IF H=136
    F=0
  ELSE
    H=H+8: MOVE Q+8,P+589,8
  ENDIF
ENDIF
POKE W,H
This section jumps the squirrel left and right. It moves the player in 8 columns increments and selects which pixel graphic to display (either left or right facing squirrel). This was some of the first loop code I wrote. There may be a more compact way to do this with math and logical expressions, but these two IF-THEN structures do the trick and don't take up too much space. I suspect this is a bit faster because there's no multiplications that would be required in a more compact approach.

SOUND 0,0,0,0: SOUND 1,0,0,0
Part of the sound effect logic - here the jumping and climbing sounds are turned off. 

X=PEEK(53260)
IF X&8
  SOUND 0,50,10,15: K=K+K DIV 5: -MOVE P,P+964,28
ELSE :IF X&6
  EXIT :ENDIF
ENDIF
Check the collision register for either an acorn or blue jay hit. If an acorn, the play a tone, increment the score (by 20%), and erase the acorn. If a blue jay, exit the DO loop.

POSITION 6,1: ? #6;K
Update the score.

SOUND 2,H,10+(F=0),6
Play a sound with pitch based on the horizontal position of the squirrel when it is jumping. These sound effects were squeezed in at the end, which accounts for the inconsistent way they are implemented.

REPEAT :UNTIL PEEK(54283)>93
PAUSE 0
POKE 54277,S
Poor man's vertical blank interrupt (VBI). Since the rules prohibit machine code, just hand around until the VCOUNT register is mostly down the screen and then update the fine scrolling register. 
Call a PAUSE routine to sync up the code with the vertical blank (PAUSE counts v-blanks to keep time). This prevents flicker on the bottom row and tearing of the squirrel sprite while jumping. 

LOOP
End of the game loop - go back and DO it all again.

IF K>J: J=K: ENDIF
When a squirrel hits a blue jay, the EXIT shifts execution to here. Update the high score.

SOUND 2,0,0,0
Turn off the jumping sound. The other sounds are already turned off.

GOTO 1
Restart the game without resetting the high score.

Saturday, January 16, 2016

(Too) Many Projects

I have (too) many projects started and not finished. There’s the Nerf blaster mod the boy and I started - it’s getting there. I was testing some stepper motors from an old Epson printer with drivers and an Arduino. I was reminded once again to be careful when using 12 volts around a digital circuits. I’ve got a side project going for measuring static air pressure in a tube with a display for a friend. And I wrote up some simple text-based games on the girl’s TI-84 Plus CSE graphing calculator - my favorite is a Space Invaders rip off. And I started working on a vertical scroller Atari BASIC game.  All of this was before Christmas. At Christmas we got a family present of a LittleBits Cloudbit Starter Kit. That has some cool integration you can do with Minecraft. Last weekend I finally powered up an FPGA-Arduino board I got myself for my birthday right before #3 was born. I’m hoping to use it for video game emulation. Finally, the boy has broken out the Lego Mindstorms and built the R2-D2 look alike after seeing Star Wars. Now, if I can just get him to program it.

Definitely … technically … distracted.

Stepper motors

My kids were playing “Cookie Clickers” on their iPods. You know, that silly game where you click, click, and click to get cookies. Fortunately, the addiction is short lived. The game is actually an object lesson in labor and investment. Early on, you have to click to get points. Once you get enough points, you can start to buy automatic clickers. At some point, through enough investment, you don’t even bother to click. Your score grows exponentially. I look at this and think, “ah! automation!” You don’t want to dig ditches? Then go get an engineering degree, design a digger, and hire someone to drive it. Hopefully you’ve created more jobs in the process. But, I digress.

I had this idea I was going to build a laser engraver - it could happen. Along that path I got some small steppers out of an old printer and bought a CNC shield and stepper drivers for an Arduino. There’s a G-code interpreter for this unit so you can drive the motors using standard a development chain (e.g., SVG to STL to Gcode). I cobbled together a cheap (free) x-y table and tried it out - turns out the motors weren’t strong enough. I should have realized it wouldn’t work so well given the steppers were about ⅓ the size of those on my 3d printer. So here’s where I detoured. Automate the cookie clicker.

I designed and printed my own NEMA-17 bracket and a holder for a stylus. Instead of using the G-code software, I wrote my own pulse generator to trigger the driver. That and some finagling with the iPod orientation and I could click much faster than my kids. They were actually impressed with this one! Turns out the faster you click, the more bonus you get. My kids could only get +3 and my contraption got +5. They’d never seen that. So here I thought I’m on my way to unlimited wealth. Alas, periodically they game opens a pop-up offer you purchases. Oh well, it was fun, I learned to use the stepper drivers, and most importantly I had a good laugh with the kids.



This is long enough … I’ll do TI Atari 10-line BASIC games next time.





Monday, December 21, 2015

3D Christmas

Growing up we had dated Christmas ornaments on the tree for a number of years. They were silver or crystal. I think one was cross-stitched. I thought it would be good to restart that tradition in my own family - we have a couple dated ones already. So this year, I made a Christmas 2015 3D-printed wreath ornament. This is the second 3D-printed ornament on our tree.
Last year, the White House sponsored a 3D ornament contest. The contest rules required the entry to be put up on Instructables - here’s our’s. The wife and I designed the ubiquitous red ball, but embossed the first stanza of The First Snowfall by American poet James Russel Lowell into the surface:

The snow had begun in the gloaming,
   And busily all the night
Had been heaping field and highway
   With a silence deep and white.

We didn’t win. Although there was no contest this year, I went ahead and made one for ourselves.


The design is pretty much monolithic and made of three colors dictated by my stock of filament. Because my simple printer only has one print head, I had to make three jobs of it and glue the results together. I’m a bit enamored with extruded text like Robert Indiana’s LOVE sculpture. I used Inkscape to create an SVG file of the text and extruded it in Autodesk 123D. One thing I learned was I liked the text sized larger when it came to printing and building the model vs. the size it looked on the screen. Maybe it's "the camera adds 10 pounds" phenomenon. I printed the characters 30% larger than I designed them.

Not sure what will be next year’s creation. Probably something smaller so it doesn't crowd out the other ornaments we’ve collected over the years.


Monday, November 30, 2015

READY (Atari BASIC Redux)

READYI recently found an active online community of Atari 8-bit computer retro enthusiasts. Having grown up playing games on and programming an Atari 400 (1982-1985) and an 800XL (1985-1989), it’s been fun getting back into it. A couple years ago I loaded the Atari800XL emulator on my Raspberry PI to show the kids the games I used to play. They were unimpressed. Too bad, because I could beat them at Asteroids. More recently, I’ve been working on a BASIC program using the Altirra emulator on my Windows 7/10 desktop. I learned about a 10-line BASIC game programming competition on the ANTIC podcast, which gave me a goal for my retro ruminations. I’m hoping they’ll rerun the competition in 2016 so I can enter.



To prepare, I decided to brush up on my BASIC. I only ever used Atari’s BASIC (cart. on the 400 and built-in on the 800XL), but have since learned there are many more BASICs from which to choose. For this program, I’m using Turbo BASIC XL because it’s faster and supports block memory copies. When I tried to write games in junior high, I didn't know about Atari's player-missile graphics (hardware based sprites) although I did learn a little of the C64 sprites in 8th grade computer programming. This time around, I set out to learn a couple of the things I missed growing up: page flipping and hardware sprites. To use these techniques in Atari BASIC requires lots of PEEKs and POKEs and some understanding of the memory map, which probably explains why I didn't get it back then.

I asked the boy what kind of game I should write and he thought "20-ball Pong" would be hilarious. I prototyped it in Python to get the game logic down so I wouldn't have to design the game while relearning BASIC. The concept is pretty easy and Python on a modern machine is speedy. Coding up the ball motion in an emulator, I quickly re-discovered how slow Atari BASIC was and abandoned trying to use hires graphics. The game(I call this version LMNOPing!) is now in text mode with 5 inverse ATASCII characters (L-P) standing in for software sprites and a player-missile paddle. The ball motion is not smooth moving 1 space per frame, but the paddle is speedy. The game play is still really slow, but has served the purpose of learning some new (to me) programming.

Page Flipping

To create motion, an object on the screen needs to be redrawn every frame at a new location while erasing the old location. This algorithm can easily create a flickering effect. The way around it is to draw the new frame while displaying the current frame and then flipping the page to show the updated screen. My Python prototype uses this technique. Because the Atari uses memory mapped graphics in RAM, it's pretty straightforward to implement in BASIC - a number of old magazine articles cover the topic (links are below). Point the graphics chip to display buffer A while filling in buffer B. Then flip the screen by pointing to B while filling in A.

I learned an interesting feature of the clear screen (CLS) command that is probably documented somewhere, but wasn't obvious to me. In GRAPHICS 0 (text mode), and maybe in others although I didn't test it, the CLS command will put 0's into the memory starting at the graphics map pointer filling in all the way to another pointer called RAMTOP (top of memory). I thought it would just clear out 4 pages (1 KByte) of RAM. The consequences are if one points to buffer A and doesn't update RAMTOP to point to the end of buffer A, CLS will clear both A & B. (Thanks to Wade Ripkowski for pointing out this was indeed documented.)

Player Missile Graphics (Hardware Sprites)

My 8th grade computer programming teacher taught us about C64 sprites near the end of the semester. I used them in my final project, which was a Simon game. For some reason, I never learned them on the Atari. I guess I never really understood why one would want to use some blocky single color thing when there are some great graphics modes to use. Obviously, I never tried to write a program with a software sprite back then; otherwise, I would have seen them for the genius they were.

For this game, I’m going pretty simple with a basic bar that is moved vertically on the screen using the paddle controller. To move the graphic, the bytes have to be copied from one location to another and erased from their old location. Instead of tracking the move, it’s easier just to rewrite the whole column by copying a buffer with the appropriate offset. This is OK since I have plenty of RAM. I suppose in a tight 8K cartridge game this would be wasteful since I use 256 bytes just for the buffer and another 256 bytes for the sprites.

What’s Next

I squeezed this program into 8 lines for practice and might add some sound. Not sure if it’ll be an entry to the 10-liner competition, but it’s been a fun challenge.

Resources